From 125bcc1b473f98ffa87d858985486d25e1ac5e59 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 14 Sep 2021 12:13:19 +0100 Subject: [PATCH 01/50] Provisional impl and testing of central state tracker. Signed-off-by: John --- .../ViewportEditorModeStateTrackerInterface.h | 42 ++ ...ortEditorModeStateTrackerNotificationBus.h | 65 +++ .../EditorInteractionInterface.h | 33 ++ .../ViewportEditorModeStateTracker.cpp | 121 +++++ .../ViewportEditorModeStateTracker.h | 62 +++ .../aztoolsframework_files.cmake | 4 + .../Viewport/ViewportEditorModeTests.cpp | 492 ++++++++++++++++++ .../Tests/aztoolsframeworktests_files.cmake | 1 + 8 files changed, 820 insertions(+) create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerNotificationBus.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionInterface.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h create mode 100644 Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h new file mode 100644 index 0000000000..4f8b800215 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +namespace AzToolsFramework +{ + //! The AZ::Interface of the central editor mode state tracker for all viewports. + class ViewportEditorModeStateTrackerInterface + { + public: + AZ_RTTI(ViewportEditorModeStateTrackerInterface, "{7D72A4F7-2147-4ED9-A315-E456A3BE3CF6}"); + + virtual ~ViewportEditorModeStateTrackerInterface() = default; + + //! Enters the specified editor mode for the specified viewport. + virtual void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; + + //! Exits the specified editor mode for the specified viewport. + virtual void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; + + //! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr. + virtual const ViewportEditorModeStateInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; + + //! Returns the number of viewports currently being tracked. + virtual size_t GetNumTrackedViewports() const = 0; + + //! Returns true if the specified viewport is being tracked, otherwise false. + virtual bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; + + private: + }; +} // namespace AzToolsFramework + diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerNotificationBus.h new file mode 100644 index 0000000000..7b95ebc6cc --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerNotificationBus.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include +#include + +namespace AzToolsFramework +{ + //! Enumeration of each viewport editor state. + enum class ViewportEditorMode : AZ::u8 + { + Default, + Component, + Focus, + Pick + }; + + //! Viewport identifier and other relevant viewport data. + struct ViewportEditorModeInfo + { + using IdType = AzFramework::ViewportId; + IdType m_id = ViewportUi::DefaultViewportId; //!< The unique identifier for a given viewport. + }; + + //! Interface for the editor mode state of a given viewport. + class ViewportEditorModeStateInterface + { + public: + virtual ~ViewportEditorModeStateInterface() = default; + + //! Returns true if the specified editor mode is active, otherwise false. + virtual bool IsModeActive(ViewportEditorMode mode) const = 0; + }; + + //! Provides a bus to notify when the different editor modes are entered/exit. + class ViewportEditorModeNotifications + : public AZ::EBusTraits + { + public: + ////////////////////////////////////////////////////////////////////////// + // EBusTraits overrides + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; + using BusIdType = ViewportEditorModeInfo::IdType; + ////////////////////////////////////////////////////////////////////////// + + //! Notifies subscribers of the a given viewport to the entering of the specified editor mode. + virtual void OnEditorModeEnter([[maybe_unused]] const ViewportEditorModeStateInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + { + } + + //! Notifies subscribers of the a given viewport to the exiting of the specified editor mode. + virtual void OnEditorModeExit([[maybe_unused]] const ViewportEditorModeStateInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + { + } + }; + using ViewportEditorModeNotificationsBus = AZ::EBus; +} diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionInterface.h new file mode 100644 index 0000000000..70cbfd09ec --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionInterface.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +namespace AzToolsFramework +{ + /*! + * EditorInteractionInterface + * Allows systems to alter the behavior of viewport selection. + */ + class EditorInteractionInterface + { + public: + AZ_RTTI(EditorInteractionInterface, "{09276E3C-9AA6-40FF-A0B5-3D33A33F0E5A}"); + + /*! + * Allows the entity system to redirect the selection of an entity to another entity. + * It can be used to select a container when clicking on its content. + */ + virtual AZ::EntityId RedirectEntitySelection(AZ::EntityId entityId) = 0; + }; + +} // namespace AzToolsFramework + diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp new file mode 100644 index 0000000000..64e8c2bbd1 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp @@ -0,0 +1,121 @@ +/* + * 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 +#include + +namespace AzToolsFramework +{ + static constexpr const char* ViewportEditorModeLogWindow = "ViewportEditorMode"; + + void ViewportEditorModeState::SetModeActive(ViewportEditorMode mode) + { + if (const AZ::u32 modeIndex = static_cast(mode); + modeIndex < NumEditorModes) + { + m_editorModes[modeIndex] = true; + } + else + { + AZ_Error(ViewportEditorModeLogWindow, false, "Cannot activate mode %u, mode is not recognized", modeIndex) + } + } + + void ViewportEditorModeState::SetModeInactive(ViewportEditorMode mode) + { + if (const AZ::u32 modeIndex = static_cast(mode); modeIndex < NumEditorModes) + { + m_editorModes[modeIndex] = false; + } + else + { + AZ_Error(ViewportEditorModeLogWindow, false, "Cannot deactivate mode %u, mode is not recognized", modeIndex) + } + } + + bool ViewportEditorModeState::IsModeActive(ViewportEditorMode mode) const + { + return m_editorModes[static_cast(mode)]; + } + + void ViewportEditorModeStateTracker::RegisterInterface() + { + if (AZ::Interface::Get() == nullptr) + { + AZ::Interface::Register(this); + } + } + + void ViewportEditorModeStateTracker::UnregisterInterface() + { + if (AZ::Interface::Get() != nullptr) + { + AZ::Interface::Unregister(this); + } + } + + void ViewportEditorModeStateTracker::EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + { + auto& editorModeStates = m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; + AZ_Warning( + ViewportEditorModeLogWindow, !editorModeStates.IsModeActive(mode), + AZStd::string::format( + "Duplicate call to EnterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); + editorModeStates.SetModeActive(mode); + ViewportEditorModeNotificationsBus::Event( + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModeStates, mode); + } + + void ViewportEditorModeStateTracker::ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + { + ViewportEditorModeState* editorModeStates = nullptr; + if (m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id)) + { + editorModeStates = &m_viewportEditorModeStates.at(viewportEditorModeInfo.m_id); + AZ_Warning( + ViewportEditorModeLogWindow, editorModeStates->IsModeActive(mode), + AZStd::string::format( + "Duplicate call to ExitMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); + } + else + { + AZ_Warning( + ViewportEditorModeLogWindow, false, "Call to ExitMode for mode '%u' on id '%i' without precursor call to EnterMode", + static_cast(mode), viewportEditorModeInfo.m_id); + + editorModeStates = &m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; + } + + editorModeStates->SetModeInactive(mode); + ViewportEditorModeNotificationsBus::Event( + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModeStates, mode); + } + + const ViewportEditorModeStateInterface* ViewportEditorModeStateTracker::GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const + { + if (auto editorModeStates = m_viewportEditorModeStates.find(viewportEditorModeInfo.m_id); + editorModeStates != m_viewportEditorModeStates.end()) + { + return &editorModeStates->second; + } + else + { + return nullptr; + } + } + + size_t ViewportEditorModeStateTracker::GetNumTrackedViewports() const + { + return m_viewportEditorModeStates.size(); + } + + bool ViewportEditorModeStateTracker::IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const + { + return m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id) > 0; + } +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h new file mode 100644 index 0000000000..30eabdf16e --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace AzToolsFramework +{ + //! The encapsulation of the editor modes for a given viewport. + class ViewportEditorModeState + : public ViewportEditorModeStateInterface + { + public: + + //! The number of currently supported viewport editor modes. + static constexpr AZ::u8 NumEditorModes = 4; + + //! Sets the specified mode as active. + void SetModeActive(ViewportEditorMode mode); + + // Sets the specified mode as inactive. + void SetModeInactive(ViewportEditorMode mode); + + // ViewportEditorModeStateInterface ... + bool IsModeActive(ViewportEditorMode mode) const override; + private: + AZStd::array m_editorModes{}; //!< State flags to track active/inactive status of viewport editor modes. + }; + + //! The implementation of the central editor mode state tracker for all viewports. + class ViewportEditorModeStateTracker + : public ViewportEditorModeStateTrackerInterface + { + public: + //! Registers this object with the AZ::Interface. + void RegisterInterface(); + + //! Unregisters this object with the AZ::Interface. + void UnregisterInterface(); + + // ViewportEditorModeStateTrackerInterface ... + void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + const ViewportEditorModeStateInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; + size_t GetNumTrackedViewports() const override; + bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; + + private: + using ViewportEditorModeStates = AZStd::unordered_map; + ViewportEditorModeStates m_viewportEditorModeStates; //!< Editor mode state per viewport. + }; +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 2d9e75a115..9b7394a6e7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -34,6 +34,7 @@ set(FILES API/EditorAnimationSystemRequestBus.h API/EditorEntityAPI.h API/EditorLevelNotificationBus.h + API/ViewportEditorModeStateTrackerNotificationBus.h API/EditorVegetationRequestsBus.h API/EditorPythonConsoleBus.h API/EditorPythonRunnerRequestsBus.h @@ -44,6 +45,7 @@ set(FILES API/EntityCompositionNotificationBus.h API/EditorViewportIconDisplayInterface.h API/ViewPaneOptions.h + API/ViewportEditorModeStateTrackerInterface.h Application/Ticker.h Application/Ticker.cpp Application/EditorEntityManager.cpp @@ -538,6 +540,8 @@ set(FILES ViewportSelection/EditorTransformComponentSelectionRequestBus.cpp ViewportSelection/EditorVisibleEntityDataCache.h ViewportSelection/EditorVisibleEntityDataCache.cpp + ViewportSelection/ViewportEditorModeStateTracker.cpp + ViewportSelection/ViewportEditorModeStateTracker.h ToolsFileUtils/ToolsFileUtils.h AssetBrowser/AssetBrowserBus.h AssetBrowser/AssetBrowserSourceDropBus.h diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp new file mode 100644 index 0000000000..7718c596d5 --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -0,0 +1,492 @@ +/* + * 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 +#include +#include + +namespace UnitTest +{ + using ViewportEditorMode = AzToolsFramework::ViewportEditorMode; + using ViewportEditorModeState = AzToolsFramework::ViewportEditorModeState; + using ViewportEditorModeStateTracker = AzToolsFramework::ViewportEditorModeStateTracker; + using ViewportEditorModeInfo = AzToolsFramework::ViewportEditorModeInfo; + using ViewportId = ViewportEditorModeInfo::IdType; + using ViewportEditorModeStateInterface = AzToolsFramework::ViewportEditorModeStateInterface; + + void SetAllModesActive(ViewportEditorModeState& editorModeState) + { + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + editorModeState.SetModeActive(static_cast(mode)); + } + } + + void SetAllModesInactive(ViewportEditorModeState& editorModeState) + { + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + editorModeState.SetModeInactive(static_cast(mode)); + } + } + + // Fixture for testing editor mode states + class ViewportEditorModeStateTestsFixture + : public ::testing::Test + { + public: + ViewportEditorModeState m_editorModeState; + }; + + // Fixture for testing editor mode states with parameterized test arguments + class ViewportEditorModeStateTestsFixtureWithParams + : public ViewportEditorModeStateTestsFixture + , public ::testing::WithParamInterface + { + public: + void SetUp() override + { + m_selectedEditorMode = GetParam(); + } + + ViewportEditorMode m_selectedEditorMode; + }; + + // Fixture for testing the viewport editor mode state tracker + class ViewportEditorModeStateTrackerTestFixture + : public ToolsApplicationFixture + { + public: + ViewportEditorModeStateTracker m_viewportEditorModeStteTracker; + }; + + // Subscriber of viewport editor mode notifications for a single viewport that expects a single mode to be activated/deactivated + class ViewportEditorModeNotificationsBusHandler + : private AzToolsFramework::ViewportEditorModeNotificationsBus::Handler + { + public: + struct ReceivedEvents + { + bool m_onEnter = false; + bool m_onLeave = false; + }; + + using EditModeTracker = AZStd::unordered_map; + + ViewportEditorModeNotificationsBusHandler(ViewportId viewportId) + : m_viewportSubscription(viewportId) + { + AzToolsFramework::ViewportEditorModeNotificationsBus::Handler::BusConnect(m_viewportSubscription); + } + + ~ViewportEditorModeNotificationsBusHandler() + { + AzToolsFramework::ViewportEditorModeNotificationsBus::Handler::BusDisconnect(); + } + + ViewportId GetViewportSubscription() const + { + return m_viewportSubscription; + } + + const EditModeTracker& GetEditorModes() const + { + return m_editorModes; + } + + void OnEditorModeEnter([[maybe_unused]]const ViewportEditorModeStateInterface& editorModeState, ViewportEditorMode mode) override + { + m_editorModes[mode].m_onEnter = true; + } + + virtual void OnEditorModeExit([[maybe_unused]] const ViewportEditorModeStateInterface& editorModeState, ViewportEditorMode mode) override + { + m_editorModes[mode].m_onLeave = true; + } + + private: + ViewportId m_viewportSubscription; + EditModeTracker m_editorModes; + + }; + + // Fixture for testing viewport editor mode notifications publishing + class ViewportEditorModePublisherTestFixture + : public ViewportEditorModeStateTrackerTestFixture + { + public: + + void SetUpEditorFixtureImpl() override + { + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + m_editorModeHandlers[mode] = AZStd::make_unique(mode); + } + } + + void TearDownEditorFixtureImpl() override + { + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + m_editorModeHandlers[mode].reset(); + } + } + + AZStd::array, ViewportEditorModeState::NumEditorModes> m_editorModeHandlers; + }; + + TEST_F(ViewportEditorModeStateTestsFixture, NumberOfEditorModesIsEqualTo4) + { + EXPECT_EQ(ViewportEditorModeState::NumEditorModes, 4); + } + + TEST_F(ViewportEditorModeStateTestsFixture, InitialEditorModeStateHasAllInactiveModes) + { + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + EXPECT_FALSE(m_editorModeState.IsModeActive(static_cast(mode))); + } + } + + TEST_P(ViewportEditorModeStateTestsFixtureWithParams, SettingModeActiveActivatesOnlyThatMode) + { + m_editorModeState.SetModeActive(m_selectedEditorMode); + + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + const auto editorMode = static_cast(mode); + if (editorMode == m_selectedEditorMode) + { + EXPECT_TRUE(m_editorModeState.IsModeActive(static_cast(editorMode))); + } + else + { + EXPECT_FALSE(m_editorModeState.IsModeActive(static_cast(editorMode))); + } + } + } + + TEST_P(ViewportEditorModeStateTestsFixtureWithParams, SettingModeInactiveInactivatesOnlyThatMode) + { + SetAllModesActive(m_editorModeState); + m_editorModeState.SetModeInactive(m_selectedEditorMode); + + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + const auto editorMode = static_cast(mode); + if (editorMode == m_selectedEditorMode) + { + EXPECT_FALSE(m_editorModeState.IsModeActive(editorMode)); + } + else + { + EXPECT_TRUE(m_editorModeState.IsModeActive(editorMode)); + } + } + } + + TEST_P(ViewportEditorModeStateTestsFixtureWithParams, SettingMultipleModesActiveActivatesAllThoseModesNonMutuallyExclusively) + { + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes - 1; mode++) + { + // Given only the selected mode active + SetAllModesInactive(m_editorModeState); + m_editorModeState.SetModeActive(m_selectedEditorMode); + + const auto editorMode = static_cast(mode); + if (editorMode == m_selectedEditorMode) + { + continue; + } + + // When other modes are activated + m_editorModeState.SetModeActive(editorMode); + + for (auto expectedMode = 0; expectedMode < ViewportEditorModeState::NumEditorModes; expectedMode++) + { + const auto expectedEditorMode = static_cast(expectedMode); + if (expectedEditorMode == editorMode || expectedEditorMode == m_selectedEditorMode) + { + // Expect the activated modes to be active + EXPECT_TRUE(m_editorModeState.IsModeActive(expectedEditorMode)); + } + else + { + // Expect the modes not active to be inactive + EXPECT_FALSE(m_editorModeState.IsModeActive(expectedEditorMode)); + } + } + } + } + + TEST_P(ViewportEditorModeStateTestsFixtureWithParams, SettingMultipleModesInactiveInactivatesAllThoseModesNonMutuallyExclusively) + { + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes - 1; mode++) + { + // Given only the selected mode inactive + SetAllModesActive(m_editorModeState); + m_editorModeState.SetModeInactive(m_selectedEditorMode); + + const auto editorMode = static_cast(mode); + if (editorMode == m_selectedEditorMode) + { + continue; + } + + // When other modes are deactivated + m_editorModeState.SetModeInactive(editorMode); + + for (auto expectedMode = 0; expectedMode < ViewportEditorModeState::NumEditorModes; expectedMode++) + { + const auto expectedEditorMode = static_cast(expectedMode); + if (expectedEditorMode == editorMode || expectedEditorMode == m_selectedEditorMode) + { + // Expect the deactivated modes to be inactive + EXPECT_FALSE(m_editorModeState.IsModeActive(expectedEditorMode)); + } + else + { + // Expects the modes not deactivated to still be active + EXPECT_TRUE(m_editorModeState.IsModeActive(expectedEditorMode)); + } + } + } + } + + INSTANTIATE_TEST_CASE_P( + AllEditorModes, + ViewportEditorModeStateTestsFixtureWithParams, + ::testing::Values( + AzToolsFramework::ViewportEditorMode::Default, + AzToolsFramework::ViewportEditorMode::Component, + AzToolsFramework::ViewportEditorMode::Focus, + AzToolsFramework::ViewportEditorMode::Pick)); + + TEST_F(ViewportEditorModeStateTestsFixture, SettingOutOfBoundsModeActiveIssuesErrorMsg) + { + UnitTest::TestRunner::Instance().StartAssertTests(); + m_editorModeState.SetModeActive(static_cast(ViewportEditorModeState::NumEditorModes)); + EXPECT_EQ(1, UnitTest::TestRunner::Instance().StopAssertTests()); + } + + TEST_F(ViewportEditorModeStateTestsFixture, SettingOutOfBoundsModeInactiveIssuesErrorMsg) + { + UnitTest::TestRunner::Instance().StartAssertTests(); + m_editorModeState.SetModeInactive(static_cast(ViewportEditorModeState::NumEditorModes)); + EXPECT_EQ(1, UnitTest::TestRunner::Instance().StopAssertTests()); + } + + TEST_F(ViewportEditorModeStateTrackerTestFixture, InitialCentralStateTrackerHasNoViewportEditorModeStates) + { + EXPECT_EQ(m_viewportEditorModeStteTracker.GetNumTrackedViewports(), 0); + } + + TEST_F(ViewportEditorModeStateTrackerTestFixture, EnteringViewportEditorModeForNonExistentIdCreatesViewportEditorModeStateForThatId) + { + // Given a viewport not currently being tracked + const ViewportId viewportid = 0; + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + + // When a mode is activated for that viewport + const auto editorMode = ViewportEditorMode::Default; + m_viewportEditorModeStteTracker.EnterMode({ viewportid }, editorMode); + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + + // Expect that viewport to now be tracked + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_NE(viewportEditorModeState, nullptr); + + // Expect the mode for that viewport to be active + EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); + } + + TEST_F(ViewportEditorModeStateTrackerTestFixture, ExitingViewportEditorModeForNonExistentIdCreatesViewportEditorModeStateForThatIdButIssuesErrorMsg) + { + // Given a viewport not currently being tracked + const ViewportId viewportid = 0; + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + + // When a mode is deactivated for that viewport + const auto editorMode = ViewportEditorMode::Default; + UnitTest::ErrorHandler errorHandler(AZStd::string::format( + "Call to ExitMode for mode '%u' on id '%i' without precursor call to EnterMode", static_cast(editorMode), viewportid).c_str()); + m_viewportEditorModeStteTracker.ExitMode({ viewportid }, editorMode); + + // Expect a warning to be issued due to no precursor activation of that mode + EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); + + // Expect that viewport to now be tracked + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + + // Expect the mode for that viewport to be inactive + EXPECT_NE(viewportEditorModeState, nullptr); + EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); + } + + TEST_F(ViewportEditorModeStateTrackerTestFixture, GettingNonExistentViewportEditorModeStateForIdReturnsNull) + { + const ViewportId viewportid = 0; + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + } + + TEST_F(ViewportEditorModeStateTrackerTestFixture, EnteringViewportEditorModeStateForExistingIdInThatStateIssuesWarningMsg) + { + // Given a viewport not currently tracked + const ViewportId viewportid = 0; + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + + const auto editorMode = ViewportEditorMode::Default; + const auto expectedWarning = AZStd::string::format( + "Duplicate call to EnterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); + + { + UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); + + // When the mode is activated for the viewport + m_viewportEditorModeStteTracker.EnterMode({ viewportid }, editorMode); + + // Expect no warning to be issued as there is no duplicate activation + EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); + + // Expect the mode to be active for the viewport + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_NE(viewportEditorModeState, nullptr); + EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); + } + { + // When the mode is activated again for the viewport + UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); + m_viewportEditorModeStteTracker.EnterMode({ viewportid }, editorMode); + + // Expect a warning to be issued for the duplicate activation + EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); + + // Expect the mode to still be active for the viewport + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_NE(viewportEditorModeState, nullptr); + EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); + } + } + + TEST_F(ViewportEditorModeStateTrackerTestFixture, ExitingViewportEditorModeStateForExistingIdNotInThatStateIssuesWarningMsg) + { + // Given a viewport not currently tracked + const ViewportId viewportid = 0; + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + + const auto editorMode = ViewportEditorMode::Default; + const auto expectedWarning = + AZStd::string::format("Duplicate call to ExitMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); + + { + UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); + + // When the mode is activated and then deactivated for the viewport + m_viewportEditorModeStteTracker.EnterMode({ viewportid }, editorMode); + m_viewportEditorModeStteTracker.ExitMode({ viewportid }, editorMode); + + // Expect no warning to be issued as there is no duplicate deactivation + EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); + + // Expect the mode to be inctive for the viewport + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_NE(viewportEditorModeState, nullptr); + EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); + } + { + UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); + + // When the mode is deactivated again for the viewport + m_viewportEditorModeStteTracker.ExitMode({ viewportid }, editorMode); + + // Expect a warning to be issued for the duplicate deactivation + EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); + + // Expect the mode to still be inactive for the viewport + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_NE(viewportEditorModeState, nullptr); + EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); + } + } + + TEST_F( + ViewportEditorModePublisherTestFixture, + EnteringViewportEditorModeStateForExistingIdPublishesOnViewportEditorModeEnterEventForAllSubscribers) + { + // Given a set of subscribers tracking the editor modes for their exclusive viewport + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + // Expect each subscriber to have received no editor mode state changes + EXPECT_EQ(m_editorModeHandlers[mode]->GetEditorModes().size(), 0); + } + + // When each editor mode is activated by the state tracker for a specific viewport + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + const ViewportId viewportId = mode; + const ViewportEditorMode editorMode = static_cast(mode); + m_viewportEditorModeStteTracker.EnterMode({ mode }, editorMode); + } + + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + // Expect only the subscribers of each viewport to have received the editor mode activated event + const ViewportEditorMode editorMode = static_cast(mode); + const auto& editorModes = m_editorModeHandlers[mode]->GetEditorModes(); + EXPECT_EQ(editorModes.size(), 1); + EXPECT_EQ(editorModes.count(editorMode), 1); + const auto& expectedEditorModeSet = editorModes.find(editorMode); + EXPECT_NE(expectedEditorModeSet, editorModes.end()); + EXPECT_TRUE(expectedEditorModeSet->second.m_onEnter); + EXPECT_FALSE(expectedEditorModeSet->second.m_onLeave); + } + } + + TEST_F( + ViewportEditorModePublisherTestFixture, + ExitingViewportEditorModeStateForExistingIdPublishesOnViewportEditorModeExitEventForAllSubscribers) + { + // Given a set of subscribers tracking the editor modes for their exclusive viewport + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + EXPECT_EQ(m_editorModeHandlers[mode]->GetEditorModes().size(), 0); + } + + // When each editor mode is activated deactivated by the state tracker for a specific viewport + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + const ViewportId viewportId = mode; + const ViewportEditorMode editorMode = static_cast(mode); + m_viewportEditorModeStteTracker.EnterMode({ mode }, editorMode); + m_viewportEditorModeStteTracker.ExitMode({ mode }, editorMode); + } + + for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + { + // Expect only the subscribers of each viewport to have received the editor mode activated and deactivated event + const ViewportEditorMode editorMode = static_cast(mode); + const auto& editorModes = m_editorModeHandlers[mode]->GetEditorModes(); + EXPECT_EQ(editorModes.size(), 1); + EXPECT_EQ(editorModes.count(editorMode), 1); + const auto& expectedEditorModeSet = editorModes.find(editorMode); + EXPECT_NE(expectedEditorModeSet, editorModes.end()); + EXPECT_TRUE(expectedEditorModeSet->second.m_onEnter); + EXPECT_TRUE(expectedEditorModeSet->second.m_onLeave); + } + } +} diff --git a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake index 5ff41d9e6c..764afce266 100644 --- a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake +++ b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake @@ -110,6 +110,7 @@ set(FILES UI/EntityPropertyEditorTests.cpp UndoStack.cpp Viewport/ClusterTests.cpp + Viewport/ViewportEditorModeTests.cpp Viewport/ViewportScreenTests.cpp Viewport/ViewportUiClusterTests.cpp Viewport/ViewportUiDisplayTests.cpp From 02425f85772fdc31a72834669b9695ec78e0b378 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 14 Sep 2021 12:21:36 +0100 Subject: [PATCH 02/50] Add missing namespace comment. Signed-off-by: John --- .../AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 7718c596d5..cae7092a8a 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -489,4 +489,4 @@ namespace UnitTest EXPECT_TRUE(expectedEditorModeSet->second.m_onLeave); } } -} +} // namespace UnitTest From 199d857c8a447796176b959d3c5f5134ad74b1df Mon Sep 17 00:00:00 2001 From: John Date: Tue, 14 Sep 2021 17:51:23 +0100 Subject: [PATCH 03/50] ViewportEditorModeState -> ViewportEditorModes Signed-off-by: John --- ... => ViewportEditorModesTrackerInterface.h} | 10 +- ...ewportEditorModesTrackerNotificationBus.h} | 8 +- ...ker.cpp => ViewportEditorModesTracker.cpp} | 34 +++--- ...Tracker.h => ViewportEditorModesTracker.h} | 22 ++-- .../aztoolsframework_files.cmake | 8 +- .../Viewport/ViewportEditorModeTests.cpp | 106 +++++++++--------- 6 files changed, 94 insertions(+), 94 deletions(-) rename Code/Framework/AzToolsFramework/AzToolsFramework/API/{ViewportEditorModeStateTrackerInterface.h => ViewportEditorModesTrackerInterface.h} (74%) rename Code/Framework/AzToolsFramework/AzToolsFramework/API/{ViewportEditorModeStateTrackerNotificationBus.h => ViewportEditorModesTrackerNotificationBus.h} (88%) rename Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/{ViewportEditorModeStateTracker.cpp => ViewportEditorModesTracker.cpp} (68%) rename Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/{ViewportEditorModeStateTracker.h => ViewportEditorModesTracker.h} (68%) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerInterface.h similarity index 74% rename from Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h rename to Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerInterface.h index 4f8b800215..b13085bc83 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerInterface.h @@ -9,17 +9,17 @@ #pragma once #include -#include +#include namespace AzToolsFramework { //! The AZ::Interface of the central editor mode state tracker for all viewports. - class ViewportEditorModeStateTrackerInterface + class ViewportEditorModesTrackerInterface { public: - AZ_RTTI(ViewportEditorModeStateTrackerInterface, "{7D72A4F7-2147-4ED9-A315-E456A3BE3CF6}"); + AZ_RTTI(ViewportEditorModesTrackerInterface, "{7D72A4F7-2147-4ED9-A315-E456A3BE3CF6}"); - virtual ~ViewportEditorModeStateTrackerInterface() = default; + virtual ~ViewportEditorModesTrackerInterface() = default; //! Enters the specified editor mode for the specified viewport. virtual void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; @@ -28,7 +28,7 @@ namespace AzToolsFramework virtual void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; //! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr. - virtual const ViewportEditorModeStateInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; + virtual const ViewportEditorModesInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; //! Returns the number of viewports currently being tracked. virtual size_t GetNumTrackedViewports() const = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerNotificationBus.h similarity index 88% rename from Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerNotificationBus.h rename to Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerNotificationBus.h index 7b95ebc6cc..b9b5c80f39 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerNotificationBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerNotificationBus.h @@ -30,10 +30,10 @@ namespace AzToolsFramework }; //! Interface for the editor mode state of a given viewport. - class ViewportEditorModeStateInterface + class ViewportEditorModesInterface { public: - virtual ~ViewportEditorModeStateInterface() = default; + virtual ~ViewportEditorModesInterface() = default; //! Returns true if the specified editor mode is active, otherwise false. virtual bool IsModeActive(ViewportEditorMode mode) const = 0; @@ -52,12 +52,12 @@ namespace AzToolsFramework ////////////////////////////////////////////////////////////////////////// //! Notifies subscribers of the a given viewport to the entering of the specified editor mode. - virtual void OnEditorModeEnter([[maybe_unused]] const ViewportEditorModeStateInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + virtual void OnEditorModeEnter([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) { } //! Notifies subscribers of the a given viewport to the exiting of the specified editor mode. - virtual void OnEditorModeExit([[maybe_unused]] const ViewportEditorModeStateInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + virtual void OnEditorModeExit([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) { } }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.cpp similarity index 68% rename from Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp rename to Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.cpp index 64e8c2bbd1..5e6f73f963 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.cpp @@ -6,14 +6,14 @@ * */ -#include -#include +#include +#include namespace AzToolsFramework { static constexpr const char* ViewportEditorModeLogWindow = "ViewportEditorMode"; - void ViewportEditorModeState::SetModeActive(ViewportEditorMode mode) + void ViewportEditorModes::SetModeActive(ViewportEditorMode mode) { if (const AZ::u32 modeIndex = static_cast(mode); modeIndex < NumEditorModes) @@ -26,7 +26,7 @@ namespace AzToolsFramework } } - void ViewportEditorModeState::SetModeInactive(ViewportEditorMode mode) + void ViewportEditorModes::SetModeInactive(ViewportEditorMode mode) { if (const AZ::u32 modeIndex = static_cast(mode); modeIndex < NumEditorModes) { @@ -38,28 +38,28 @@ namespace AzToolsFramework } } - bool ViewportEditorModeState::IsModeActive(ViewportEditorMode mode) const + bool ViewportEditorModes::IsModeActive(ViewportEditorMode mode) const { return m_editorModes[static_cast(mode)]; } - void ViewportEditorModeStateTracker::RegisterInterface() + void ViewportEditorModesTracker::RegisterInterface() { - if (AZ::Interface::Get() == nullptr) + if (AZ::Interface::Get() == nullptr) { - AZ::Interface::Register(this); + AZ::Interface::Register(this); } } - void ViewportEditorModeStateTracker::UnregisterInterface() + void ViewportEditorModesTracker::UnregisterInterface() { - if (AZ::Interface::Get() != nullptr) + if (AZ::Interface::Get() != nullptr) { - AZ::Interface::Unregister(this); + AZ::Interface::Unregister(this); } } - void ViewportEditorModeStateTracker::EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + void ViewportEditorModesTracker::EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { auto& editorModeStates = m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; AZ_Warning( @@ -71,9 +71,9 @@ namespace AzToolsFramework viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModeStates, mode); } - void ViewportEditorModeStateTracker::ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + void ViewportEditorModesTracker::ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { - ViewportEditorModeState* editorModeStates = nullptr; + ViewportEditorModes* editorModeStates = nullptr; if (m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id)) { editorModeStates = &m_viewportEditorModeStates.at(viewportEditorModeInfo.m_id); @@ -96,7 +96,7 @@ namespace AzToolsFramework viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModeStates, mode); } - const ViewportEditorModeStateInterface* ViewportEditorModeStateTracker::GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const + const ViewportEditorModesInterface* ViewportEditorModesTracker::GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const { if (auto editorModeStates = m_viewportEditorModeStates.find(viewportEditorModeInfo.m_id); editorModeStates != m_viewportEditorModeStates.end()) @@ -109,12 +109,12 @@ namespace AzToolsFramework } } - size_t ViewportEditorModeStateTracker::GetNumTrackedViewports() const + size_t ViewportEditorModesTracker::GetNumTrackedViewports() const { return m_viewportEditorModeStates.size(); } - bool ViewportEditorModeStateTracker::IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const + bool ViewportEditorModesTracker::IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const { return m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id) > 0; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.h similarity index 68% rename from Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h rename to Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.h index 30eabdf16e..4acd7f09b6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.h @@ -11,14 +11,14 @@ #include #include #include -#include -#include +#include +#include namespace AzToolsFramework { //! The encapsulation of the editor modes for a given viewport. - class ViewportEditorModeState - : public ViewportEditorModeStateInterface + class ViewportEditorModes + : public ViewportEditorModesInterface { public: @@ -31,15 +31,15 @@ namespace AzToolsFramework // Sets the specified mode as inactive. void SetModeInactive(ViewportEditorMode mode); - // ViewportEditorModeStateInterface ... + // ViewportEditorModesInterface ... bool IsModeActive(ViewportEditorMode mode) const override; private: AZStd::array m_editorModes{}; //!< State flags to track active/inactive status of viewport editor modes. }; //! The implementation of the central editor mode state tracker for all viewports. - class ViewportEditorModeStateTracker - : public ViewportEditorModeStateTrackerInterface + class ViewportEditorModesTracker + : public ViewportEditorModesTrackerInterface { public: //! Registers this object with the AZ::Interface. @@ -48,15 +48,15 @@ namespace AzToolsFramework //! Unregisters this object with the AZ::Interface. void UnregisterInterface(); - // ViewportEditorModeStateTrackerInterface ... + // ViewportEditorModesTrackerInterface ... void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; - const ViewportEditorModeStateInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; + const ViewportEditorModesInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; size_t GetNumTrackedViewports() const override; bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; private: - using ViewportEditorModeStates = AZStd::unordered_map; - ViewportEditorModeStates m_viewportEditorModeStates; //!< Editor mode state per viewport. + using ViewportEditorModess = AZStd::unordered_map; + ViewportEditorModess m_viewportEditorModeStates; //!< Editor mode state per viewport. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 9b7394a6e7..65bc4e6b50 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -34,7 +34,7 @@ set(FILES API/EditorAnimationSystemRequestBus.h API/EditorEntityAPI.h API/EditorLevelNotificationBus.h - API/ViewportEditorModeStateTrackerNotificationBus.h + API/ViewportEditorModesTrackerNotificationBus.h API/EditorVegetationRequestsBus.h API/EditorPythonConsoleBus.h API/EditorPythonRunnerRequestsBus.h @@ -45,7 +45,7 @@ set(FILES API/EntityCompositionNotificationBus.h API/EditorViewportIconDisplayInterface.h API/ViewPaneOptions.h - API/ViewportEditorModeStateTrackerInterface.h + API/ViewportEditorModesTrackerInterface.h Application/Ticker.h Application/Ticker.cpp Application/EditorEntityManager.cpp @@ -540,8 +540,8 @@ set(FILES ViewportSelection/EditorTransformComponentSelectionRequestBus.cpp ViewportSelection/EditorVisibleEntityDataCache.h ViewportSelection/EditorVisibleEntityDataCache.cpp - ViewportSelection/ViewportEditorModeStateTracker.cpp - ViewportSelection/ViewportEditorModeStateTracker.h + ViewportSelection/ViewportEditorModesTracker.cpp + ViewportSelection/ViewportEditorModesTracker.h ToolsFileUtils/ToolsFileUtils.h AssetBrowser/AssetBrowserBus.h AssetBrowser/AssetBrowserSourceDropBus.h diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index cae7092a8a..777fbe0585 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -8,44 +8,44 @@ #include #include -#include +#include namespace UnitTest { using ViewportEditorMode = AzToolsFramework::ViewportEditorMode; - using ViewportEditorModeState = AzToolsFramework::ViewportEditorModeState; - using ViewportEditorModeStateTracker = AzToolsFramework::ViewportEditorModeStateTracker; + using ViewportEditorModes = AzToolsFramework::ViewportEditorModes; + using ViewportEditorModesTracker = AzToolsFramework::ViewportEditorModesTracker; using ViewportEditorModeInfo = AzToolsFramework::ViewportEditorModeInfo; using ViewportId = ViewportEditorModeInfo::IdType; - using ViewportEditorModeStateInterface = AzToolsFramework::ViewportEditorModeStateInterface; + using ViewportEditorModesInterface = AzToolsFramework::ViewportEditorModesInterface; - void SetAllModesActive(ViewportEditorModeState& editorModeState) + void SetAllModesActive(ViewportEditorModes& editorModeState) { - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { editorModeState.SetModeActive(static_cast(mode)); } } - void SetAllModesInactive(ViewportEditorModeState& editorModeState) + void SetAllModesInactive(ViewportEditorModes& editorModeState) { - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { editorModeState.SetModeInactive(static_cast(mode)); } } // Fixture for testing editor mode states - class ViewportEditorModeStateTestsFixture + class ViewportEditorModesTestsFixture : public ::testing::Test { public: - ViewportEditorModeState m_editorModeState; + ViewportEditorModes m_editorModeState; }; // Fixture for testing editor mode states with parameterized test arguments - class ViewportEditorModeStateTestsFixtureWithParams - : public ViewportEditorModeStateTestsFixture + class ViewportEditorModesTestsFixtureWithParams + : public ViewportEditorModesTestsFixture , public ::testing::WithParamInterface { public: @@ -58,11 +58,11 @@ namespace UnitTest }; // Fixture for testing the viewport editor mode state tracker - class ViewportEditorModeStateTrackerTestFixture + class ViewportEditorModesTrackerTestFixture : public ToolsApplicationFixture { public: - ViewportEditorModeStateTracker m_viewportEditorModeStteTracker; + ViewportEditorModesTracker m_viewportEditorModeStteTracker; }; // Subscriber of viewport editor mode notifications for a single viewport that expects a single mode to be activated/deactivated @@ -99,12 +99,12 @@ namespace UnitTest return m_editorModes; } - void OnEditorModeEnter([[maybe_unused]]const ViewportEditorModeStateInterface& editorModeState, ViewportEditorMode mode) override + void OnEditorModeEnter([[maybe_unused]]const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override { m_editorModes[mode].m_onEnter = true; } - virtual void OnEditorModeExit([[maybe_unused]] const ViewportEditorModeStateInterface& editorModeState, ViewportEditorMode mode) override + virtual void OnEditorModeExit([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override { m_editorModes[mode].m_onLeave = true; } @@ -117,13 +117,13 @@ namespace UnitTest // Fixture for testing viewport editor mode notifications publishing class ViewportEditorModePublisherTestFixture - : public ViewportEditorModeStateTrackerTestFixture + : public ViewportEditorModesTrackerTestFixture { public: void SetUpEditorFixtureImpl() override { - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { m_editorModeHandlers[mode] = AZStd::make_unique(mode); } @@ -131,33 +131,33 @@ namespace UnitTest void TearDownEditorFixtureImpl() override { - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { m_editorModeHandlers[mode].reset(); } } - AZStd::array, ViewportEditorModeState::NumEditorModes> m_editorModeHandlers; + AZStd::array, ViewportEditorModes::NumEditorModes> m_editorModeHandlers; }; - TEST_F(ViewportEditorModeStateTestsFixture, NumberOfEditorModesIsEqualTo4) + TEST_F(ViewportEditorModesTestsFixture, NumberOfEditorModesIsEqualTo4) { - EXPECT_EQ(ViewportEditorModeState::NumEditorModes, 4); + EXPECT_EQ(ViewportEditorModes::NumEditorModes, 4); } - TEST_F(ViewportEditorModeStateTestsFixture, InitialEditorModeStateHasAllInactiveModes) + TEST_F(ViewportEditorModesTestsFixture, InitialEditorModeStateHasAllInactiveModes) { - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { EXPECT_FALSE(m_editorModeState.IsModeActive(static_cast(mode))); } } - TEST_P(ViewportEditorModeStateTestsFixtureWithParams, SettingModeActiveActivatesOnlyThatMode) + TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeActiveActivatesOnlyThatMode) { m_editorModeState.SetModeActive(m_selectedEditorMode); - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { const auto editorMode = static_cast(mode); if (editorMode == m_selectedEditorMode) @@ -171,12 +171,12 @@ namespace UnitTest } } - TEST_P(ViewportEditorModeStateTestsFixtureWithParams, SettingModeInactiveInactivatesOnlyThatMode) + TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeInactiveInactivatesOnlyThatMode) { SetAllModesActive(m_editorModeState); m_editorModeState.SetModeInactive(m_selectedEditorMode); - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { const auto editorMode = static_cast(mode); if (editorMode == m_selectedEditorMode) @@ -190,9 +190,9 @@ namespace UnitTest } } - TEST_P(ViewportEditorModeStateTestsFixtureWithParams, SettingMultipleModesActiveActivatesAllThoseModesNonMutuallyExclusively) + TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingMultipleModesActiveActivatesAllThoseModesNonMutuallyExclusively) { - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes - 1; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes - 1; mode++) { // Given only the selected mode active SetAllModesInactive(m_editorModeState); @@ -207,7 +207,7 @@ namespace UnitTest // When other modes are activated m_editorModeState.SetModeActive(editorMode); - for (auto expectedMode = 0; expectedMode < ViewportEditorModeState::NumEditorModes; expectedMode++) + for (auto expectedMode = 0; expectedMode < ViewportEditorModes::NumEditorModes; expectedMode++) { const auto expectedEditorMode = static_cast(expectedMode); if (expectedEditorMode == editorMode || expectedEditorMode == m_selectedEditorMode) @@ -224,9 +224,9 @@ namespace UnitTest } } - TEST_P(ViewportEditorModeStateTestsFixtureWithParams, SettingMultipleModesInactiveInactivatesAllThoseModesNonMutuallyExclusively) + TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingMultipleModesInactiveInactivatesAllThoseModesNonMutuallyExclusively) { - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes - 1; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes - 1; mode++) { // Given only the selected mode inactive SetAllModesActive(m_editorModeState); @@ -241,7 +241,7 @@ namespace UnitTest // When other modes are deactivated m_editorModeState.SetModeInactive(editorMode); - for (auto expectedMode = 0; expectedMode < ViewportEditorModeState::NumEditorModes; expectedMode++) + for (auto expectedMode = 0; expectedMode < ViewportEditorModes::NumEditorModes; expectedMode++) { const auto expectedEditorMode = static_cast(expectedMode); if (expectedEditorMode == editorMode || expectedEditorMode == m_selectedEditorMode) @@ -260,33 +260,33 @@ namespace UnitTest INSTANTIATE_TEST_CASE_P( AllEditorModes, - ViewportEditorModeStateTestsFixtureWithParams, + ViewportEditorModesTestsFixtureWithParams, ::testing::Values( AzToolsFramework::ViewportEditorMode::Default, AzToolsFramework::ViewportEditorMode::Component, AzToolsFramework::ViewportEditorMode::Focus, AzToolsFramework::ViewportEditorMode::Pick)); - TEST_F(ViewportEditorModeStateTestsFixture, SettingOutOfBoundsModeActiveIssuesErrorMsg) + TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeActiveIssuesErrorMsg) { UnitTest::TestRunner::Instance().StartAssertTests(); - m_editorModeState.SetModeActive(static_cast(ViewportEditorModeState::NumEditorModes)); + m_editorModeState.SetModeActive(static_cast(ViewportEditorModes::NumEditorModes)); EXPECT_EQ(1, UnitTest::TestRunner::Instance().StopAssertTests()); } - TEST_F(ViewportEditorModeStateTestsFixture, SettingOutOfBoundsModeInactiveIssuesErrorMsg) + TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeInactiveIssuesErrorMsg) { UnitTest::TestRunner::Instance().StartAssertTests(); - m_editorModeState.SetModeInactive(static_cast(ViewportEditorModeState::NumEditorModes)); + m_editorModeState.SetModeInactive(static_cast(ViewportEditorModes::NumEditorModes)); EXPECT_EQ(1, UnitTest::TestRunner::Instance().StopAssertTests()); } - TEST_F(ViewportEditorModeStateTrackerTestFixture, InitialCentralStateTrackerHasNoViewportEditorModeStates) + TEST_F(ViewportEditorModesTrackerTestFixture, InitialCentralStateTrackerHasNoViewportEditorModess) { EXPECT_EQ(m_viewportEditorModeStteTracker.GetNumTrackedViewports(), 0); } - TEST_F(ViewportEditorModeStateTrackerTestFixture, EnteringViewportEditorModeForNonExistentIdCreatesViewportEditorModeStateForThatId) + TEST_F(ViewportEditorModesTrackerTestFixture, EnteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -306,7 +306,7 @@ namespace UnitTest EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } - TEST_F(ViewportEditorModeStateTrackerTestFixture, ExitingViewportEditorModeForNonExistentIdCreatesViewportEditorModeStateForThatIdButIssuesErrorMsg) + TEST_F(ViewportEditorModesTrackerTestFixture, ExitingViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButIssuesErrorMsg) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -331,14 +331,14 @@ namespace UnitTest EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); } - TEST_F(ViewportEditorModeStateTrackerTestFixture, GettingNonExistentViewportEditorModeStateForIdReturnsNull) + TEST_F(ViewportEditorModesTrackerTestFixture, GettingNonExistentViewportEditorModesForIdReturnsNull) { const ViewportId viewportid = 0; EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); } - TEST_F(ViewportEditorModeStateTrackerTestFixture, EnteringViewportEditorModeStateForExistingIdInThatStateIssuesWarningMsg) + TEST_F(ViewportEditorModesTrackerTestFixture, EnteringViewportEditorModesForExistingIdInThatStateIssuesWarningMsg) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -380,7 +380,7 @@ namespace UnitTest } } - TEST_F(ViewportEditorModeStateTrackerTestFixture, ExitingViewportEditorModeStateForExistingIdNotInThatStateIssuesWarningMsg) + TEST_F(ViewportEditorModesTrackerTestFixture, ExitingViewportEditorModesForExistingIdNotInThatStateIssuesWarningMsg) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -426,24 +426,24 @@ namespace UnitTest TEST_F( ViewportEditorModePublisherTestFixture, - EnteringViewportEditorModeStateForExistingIdPublishesOnViewportEditorModeEnterEventForAllSubscribers) + EnteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeEnterEventForAllSubscribers) { // Given a set of subscribers tracking the editor modes for their exclusive viewport - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { // Expect each subscriber to have received no editor mode state changes EXPECT_EQ(m_editorModeHandlers[mode]->GetEditorModes().size(), 0); } // When each editor mode is activated by the state tracker for a specific viewport - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); m_viewportEditorModeStteTracker.EnterMode({ mode }, editorMode); } - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { // Expect only the subscribers of each viewport to have received the editor mode activated event const ViewportEditorMode editorMode = static_cast(mode); @@ -459,16 +459,16 @@ namespace UnitTest TEST_F( ViewportEditorModePublisherTestFixture, - ExitingViewportEditorModeStateForExistingIdPublishesOnViewportEditorModeExitEventForAllSubscribers) + ExitingViewportEditorModesForExistingIdPublishesOnViewportEditorModeExitEventForAllSubscribers) { // Given a set of subscribers tracking the editor modes for their exclusive viewport - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { EXPECT_EQ(m_editorModeHandlers[mode]->GetEditorModes().size(), 0); } // When each editor mode is activated deactivated by the state tracker for a specific viewport - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); @@ -476,7 +476,7 @@ namespace UnitTest m_viewportEditorModeStteTracker.ExitMode({ mode }, editorMode); } - for (auto mode = 0; mode < ViewportEditorModeState::NumEditorModes; mode++) + for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { // Expect only the subscribers of each viewport to have received the editor mode activated and deactivated event const ViewportEditorMode editorMode = static_cast(mode); From 9553f4cc0f3d66578b85bc64d9dd12dfd541f51d Mon Sep 17 00:00:00 2001 From: John Date: Tue, 14 Sep 2021 18:56:41 +0100 Subject: [PATCH 04/50] ViewportEditorModesTracker -> ViewportEditorModeTracker Signed-off-by: John --- ...ViewportEditorModeStateTrackerInterface.h} | 8 +- .../API/ViewportEditorModeTrackerInterface.h | 42 ++++++ ...iewportEditorModeTrackerNotificationBus.h} | 0 ...cpp => ViewportEditorModeStateTracker.cpp} | 26 ++-- ...ker.h => ViewportEditorModeStateTracker.h} | 10 +- .../ViewportEditorModeTracker.cpp | 121 ++++++++++++++++++ .../ViewportEditorModeTracker.h | 62 +++++++++ .../aztoolsframework_files.cmake | 8 +- .../Viewport/ViewportEditorModeTests.cpp | 22 ++-- 9 files changed, 262 insertions(+), 37 deletions(-) rename Code/Framework/AzToolsFramework/AzToolsFramework/API/{ViewportEditorModesTrackerInterface.h => ViewportEditorModeStateTrackerInterface.h} (83%) create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h rename Code/Framework/AzToolsFramework/AzToolsFramework/API/{ViewportEditorModesTrackerNotificationBus.h => ViewportEditorModeTrackerNotificationBus.h} (100%) rename Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/{ViewportEditorModesTracker.cpp => ViewportEditorModeStateTracker.cpp} (76%) rename Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/{ViewportEditorModesTracker.h => ViewportEditorModeStateTracker.h} (88%) create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h similarity index 83% rename from Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerInterface.h rename to Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h index b13085bc83..09a39b1ec1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h @@ -9,17 +9,17 @@ #pragma once #include -#include +#include namespace AzToolsFramework { //! The AZ::Interface of the central editor mode state tracker for all viewports. - class ViewportEditorModesTrackerInterface + class ViewportEditorModeTrackerInterface { public: - AZ_RTTI(ViewportEditorModesTrackerInterface, "{7D72A4F7-2147-4ED9-A315-E456A3BE3CF6}"); + AZ_RTTI(ViewportEditorModeTrackerInterface, "{7D72A4F7-2147-4ED9-A315-E456A3BE3CF6}"); - virtual ~ViewportEditorModesTrackerInterface() = default; + virtual ~ViewportEditorModeTrackerInterface() = default; //! Enters the specified editor mode for the specified viewport. virtual void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h new file mode 100644 index 0000000000..09a39b1ec1 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +namespace AzToolsFramework +{ + //! The AZ::Interface of the central editor mode state tracker for all viewports. + class ViewportEditorModeTrackerInterface + { + public: + AZ_RTTI(ViewportEditorModeTrackerInterface, "{7D72A4F7-2147-4ED9-A315-E456A3BE3CF6}"); + + virtual ~ViewportEditorModeTrackerInterface() = default; + + //! Enters the specified editor mode for the specified viewport. + virtual void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; + + //! Exits the specified editor mode for the specified viewport. + virtual void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; + + //! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr. + virtual const ViewportEditorModesInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; + + //! Returns the number of viewports currently being tracked. + virtual size_t GetNumTrackedViewports() const = 0; + + //! Returns true if the specified viewport is being tracked, otherwise false. + virtual bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; + + private: + }; +} // namespace AzToolsFramework + diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h similarity index 100% rename from Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModesTrackerNotificationBus.h rename to Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp similarity index 76% rename from Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.cpp rename to Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp index 5e6f73f963..5c9104ab18 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp @@ -6,8 +6,8 @@ * */ -#include -#include +#include +#include namespace AzToolsFramework { @@ -43,23 +43,23 @@ namespace AzToolsFramework return m_editorModes[static_cast(mode)]; } - void ViewportEditorModesTracker::RegisterInterface() + void ViewportEditorModeTracker::RegisterInterface() { - if (AZ::Interface::Get() == nullptr) + if (AZ::Interface::Get() == nullptr) { - AZ::Interface::Register(this); + AZ::Interface::Register(this); } } - void ViewportEditorModesTracker::UnregisterInterface() + void ViewportEditorModeTracker::UnregisterInterface() { - if (AZ::Interface::Get() != nullptr) + if (AZ::Interface::Get() != nullptr) { - AZ::Interface::Unregister(this); + AZ::Interface::Unregister(this); } } - void ViewportEditorModesTracker::EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + void ViewportEditorModeTracker::EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { auto& editorModeStates = m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; AZ_Warning( @@ -71,7 +71,7 @@ namespace AzToolsFramework viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModeStates, mode); } - void ViewportEditorModesTracker::ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + void ViewportEditorModeTracker::ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { ViewportEditorModes* editorModeStates = nullptr; if (m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id)) @@ -96,7 +96,7 @@ namespace AzToolsFramework viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModeStates, mode); } - const ViewportEditorModesInterface* ViewportEditorModesTracker::GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const + const ViewportEditorModesInterface* ViewportEditorModeTracker::GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const { if (auto editorModeStates = m_viewportEditorModeStates.find(viewportEditorModeInfo.m_id); editorModeStates != m_viewportEditorModeStates.end()) @@ -109,12 +109,12 @@ namespace AzToolsFramework } } - size_t ViewportEditorModesTracker::GetNumTrackedViewports() const + size_t ViewportEditorModeTracker::GetNumTrackedViewports() const { return m_viewportEditorModeStates.size(); } - bool ViewportEditorModesTracker::IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const + bool ViewportEditorModeTracker::IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const { return m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id) > 0; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h similarity index 88% rename from Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.h rename to Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h index 4acd7f09b6..23c02dbcdf 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModesTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h @@ -11,8 +11,8 @@ #include #include #include -#include -#include +#include +#include namespace AzToolsFramework { @@ -38,8 +38,8 @@ namespace AzToolsFramework }; //! The implementation of the central editor mode state tracker for all viewports. - class ViewportEditorModesTracker - : public ViewportEditorModesTrackerInterface + class ViewportEditorModeTracker + : public ViewportEditorModeTrackerInterface { public: //! Registers this object with the AZ::Interface. @@ -48,7 +48,7 @@ namespace AzToolsFramework //! Unregisters this object with the AZ::Interface. void UnregisterInterface(); - // ViewportEditorModesTrackerInterface ... + // ViewportEditorModeTrackerInterface ... void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; const ViewportEditorModesInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp new file mode 100644 index 0000000000..5c9104ab18 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -0,0 +1,121 @@ +/* + * 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 +#include + +namespace AzToolsFramework +{ + static constexpr const char* ViewportEditorModeLogWindow = "ViewportEditorMode"; + + void ViewportEditorModes::SetModeActive(ViewportEditorMode mode) + { + if (const AZ::u32 modeIndex = static_cast(mode); + modeIndex < NumEditorModes) + { + m_editorModes[modeIndex] = true; + } + else + { + AZ_Error(ViewportEditorModeLogWindow, false, "Cannot activate mode %u, mode is not recognized", modeIndex) + } + } + + void ViewportEditorModes::SetModeInactive(ViewportEditorMode mode) + { + if (const AZ::u32 modeIndex = static_cast(mode); modeIndex < NumEditorModes) + { + m_editorModes[modeIndex] = false; + } + else + { + AZ_Error(ViewportEditorModeLogWindow, false, "Cannot deactivate mode %u, mode is not recognized", modeIndex) + } + } + + bool ViewportEditorModes::IsModeActive(ViewportEditorMode mode) const + { + return m_editorModes[static_cast(mode)]; + } + + void ViewportEditorModeTracker::RegisterInterface() + { + if (AZ::Interface::Get() == nullptr) + { + AZ::Interface::Register(this); + } + } + + void ViewportEditorModeTracker::UnregisterInterface() + { + if (AZ::Interface::Get() != nullptr) + { + AZ::Interface::Unregister(this); + } + } + + void ViewportEditorModeTracker::EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + { + auto& editorModeStates = m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; + AZ_Warning( + ViewportEditorModeLogWindow, !editorModeStates.IsModeActive(mode), + AZStd::string::format( + "Duplicate call to EnterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); + editorModeStates.SetModeActive(mode); + ViewportEditorModeNotificationsBus::Event( + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModeStates, mode); + } + + void ViewportEditorModeTracker::ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + { + ViewportEditorModes* editorModeStates = nullptr; + if (m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id)) + { + editorModeStates = &m_viewportEditorModeStates.at(viewportEditorModeInfo.m_id); + AZ_Warning( + ViewportEditorModeLogWindow, editorModeStates->IsModeActive(mode), + AZStd::string::format( + "Duplicate call to ExitMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); + } + else + { + AZ_Warning( + ViewportEditorModeLogWindow, false, "Call to ExitMode for mode '%u' on id '%i' without precursor call to EnterMode", + static_cast(mode), viewportEditorModeInfo.m_id); + + editorModeStates = &m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; + } + + editorModeStates->SetModeInactive(mode); + ViewportEditorModeNotificationsBus::Event( + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModeStates, mode); + } + + const ViewportEditorModesInterface* ViewportEditorModeTracker::GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const + { + if (auto editorModeStates = m_viewportEditorModeStates.find(viewportEditorModeInfo.m_id); + editorModeStates != m_viewportEditorModeStates.end()) + { + return &editorModeStates->second; + } + else + { + return nullptr; + } + } + + size_t ViewportEditorModeTracker::GetNumTrackedViewports() const + { + return m_viewportEditorModeStates.size(); + } + + bool ViewportEditorModeTracker::IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const + { + return m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id) > 0; + } +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h new file mode 100644 index 0000000000..23c02dbcdf --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace AzToolsFramework +{ + //! The encapsulation of the editor modes for a given viewport. + class ViewportEditorModes + : public ViewportEditorModesInterface + { + public: + + //! The number of currently supported viewport editor modes. + static constexpr AZ::u8 NumEditorModes = 4; + + //! Sets the specified mode as active. + void SetModeActive(ViewportEditorMode mode); + + // Sets the specified mode as inactive. + void SetModeInactive(ViewportEditorMode mode); + + // ViewportEditorModesInterface ... + bool IsModeActive(ViewportEditorMode mode) const override; + private: + AZStd::array m_editorModes{}; //!< State flags to track active/inactive status of viewport editor modes. + }; + + //! The implementation of the central editor mode state tracker for all viewports. + class ViewportEditorModeTracker + : public ViewportEditorModeTrackerInterface + { + public: + //! Registers this object with the AZ::Interface. + void RegisterInterface(); + + //! Unregisters this object with the AZ::Interface. + void UnregisterInterface(); + + // ViewportEditorModeTrackerInterface ... + void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + const ViewportEditorModesInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; + size_t GetNumTrackedViewports() const override; + bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; + + private: + using ViewportEditorModess = AZStd::unordered_map; + ViewportEditorModess m_viewportEditorModeStates; //!< Editor mode state per viewport. + }; +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 65bc4e6b50..3932190d8e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -34,7 +34,7 @@ set(FILES API/EditorAnimationSystemRequestBus.h API/EditorEntityAPI.h API/EditorLevelNotificationBus.h - API/ViewportEditorModesTrackerNotificationBus.h + API/ViewportEditorModeTrackerNotificationBus.h API/EditorVegetationRequestsBus.h API/EditorPythonConsoleBus.h API/EditorPythonRunnerRequestsBus.h @@ -45,7 +45,7 @@ set(FILES API/EntityCompositionNotificationBus.h API/EditorViewportIconDisplayInterface.h API/ViewPaneOptions.h - API/ViewportEditorModesTrackerInterface.h + API/ViewportEditorModeTrackerInterface.h Application/Ticker.h Application/Ticker.cpp Application/EditorEntityManager.cpp @@ -540,8 +540,8 @@ set(FILES ViewportSelection/EditorTransformComponentSelectionRequestBus.cpp ViewportSelection/EditorVisibleEntityDataCache.h ViewportSelection/EditorVisibleEntityDataCache.cpp - ViewportSelection/ViewportEditorModesTracker.cpp - ViewportSelection/ViewportEditorModesTracker.h + ViewportSelection/ViewportEditorModeTracker.cpp + ViewportSelection/ViewportEditorModeTracker.h ToolsFileUtils/ToolsFileUtils.h AssetBrowser/AssetBrowserBus.h AssetBrowser/AssetBrowserSourceDropBus.h diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 777fbe0585..63f975acdc 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -8,13 +8,13 @@ #include #include -#include +#include namespace UnitTest { using ViewportEditorMode = AzToolsFramework::ViewportEditorMode; using ViewportEditorModes = AzToolsFramework::ViewportEditorModes; - using ViewportEditorModesTracker = AzToolsFramework::ViewportEditorModesTracker; + using ViewportEditorModeTracker = AzToolsFramework::ViewportEditorModeTracker; using ViewportEditorModeInfo = AzToolsFramework::ViewportEditorModeInfo; using ViewportId = ViewportEditorModeInfo::IdType; using ViewportEditorModesInterface = AzToolsFramework::ViewportEditorModesInterface; @@ -58,11 +58,11 @@ namespace UnitTest }; // Fixture for testing the viewport editor mode state tracker - class ViewportEditorModesTrackerTestFixture + class ViewportEditorModeTrackerTestFixture : public ToolsApplicationFixture { public: - ViewportEditorModesTracker m_viewportEditorModeStteTracker; + ViewportEditorModeTracker m_viewportEditorModeStteTracker; }; // Subscriber of viewport editor mode notifications for a single viewport that expects a single mode to be activated/deactivated @@ -117,7 +117,7 @@ namespace UnitTest // Fixture for testing viewport editor mode notifications publishing class ViewportEditorModePublisherTestFixture - : public ViewportEditorModesTrackerTestFixture + : public ViewportEditorModeTrackerTestFixture { public: @@ -281,12 +281,12 @@ namespace UnitTest EXPECT_EQ(1, UnitTest::TestRunner::Instance().StopAssertTests()); } - TEST_F(ViewportEditorModesTrackerTestFixture, InitialCentralStateTrackerHasNoViewportEditorModess) + TEST_F(ViewportEditorModeTrackerTestFixture, InitialCentralStateTrackerHasNoViewportEditorModess) { EXPECT_EQ(m_viewportEditorModeStteTracker.GetNumTrackedViewports(), 0); } - TEST_F(ViewportEditorModesTrackerTestFixture, EnteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) + TEST_F(ViewportEditorModeTrackerTestFixture, EnteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -306,7 +306,7 @@ namespace UnitTest EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } - TEST_F(ViewportEditorModesTrackerTestFixture, ExitingViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButIssuesErrorMsg) + TEST_F(ViewportEditorModeTrackerTestFixture, ExitingViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButIssuesErrorMsg) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -331,14 +331,14 @@ namespace UnitTest EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); } - TEST_F(ViewportEditorModesTrackerTestFixture, GettingNonExistentViewportEditorModesForIdReturnsNull) + TEST_F(ViewportEditorModeTrackerTestFixture, GettingNonExistentViewportEditorModesForIdReturnsNull) { const ViewportId viewportid = 0; EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); } - TEST_F(ViewportEditorModesTrackerTestFixture, EnteringViewportEditorModesForExistingIdInThatStateIssuesWarningMsg) + TEST_F(ViewportEditorModeTrackerTestFixture, EnteringViewportEditorModesForExistingIdInThatStateIssuesWarningMsg) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -380,7 +380,7 @@ namespace UnitTest } } - TEST_F(ViewportEditorModesTrackerTestFixture, ExitingViewportEditorModesForExistingIdNotInThatStateIssuesWarningMsg) + TEST_F(ViewportEditorModeTrackerTestFixture, ExitingViewportEditorModesForExistingIdNotInThatStateIssuesWarningMsg) { // Given a viewport not currently tracked const ViewportId viewportid = 0; From 35a228b08f988bc219a67fc78f63253e69a65984 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 14 Sep 2021 18:57:36 +0100 Subject: [PATCH 05/50] GetEditorModeState ->GetViewportEditorModes Signed-off-by: John --- .../ViewportEditorModeStateTrackerInterface.h | 2 +- .../API/ViewportEditorModeTrackerInterface.h | 2 +- .../ViewportEditorModeStateTracker.cpp | 2 +- .../ViewportEditorModeStateTracker.h | 2 +- .../ViewportEditorModeTracker.cpp | 2 +- .../ViewportEditorModeTracker.h | 2 +- .../Viewport/ViewportEditorModeTests.cpp | 22 +++++++++---------- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h index 09a39b1ec1..706fd98c5e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h @@ -28,7 +28,7 @@ namespace AzToolsFramework virtual void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; //! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr. - virtual const ViewportEditorModesInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; + virtual const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; //! Returns the number of viewports currently being tracked. virtual size_t GetNumTrackedViewports() const = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h index 09a39b1ec1..706fd98c5e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h @@ -28,7 +28,7 @@ namespace AzToolsFramework virtual void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; //! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr. - virtual const ViewportEditorModesInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; + virtual const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; //! Returns the number of viewports currently being tracked. virtual size_t GetNumTrackedViewports() const = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp index 5c9104ab18..e78f564c9d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp @@ -96,7 +96,7 @@ namespace AzToolsFramework viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModeStates, mode); } - const ViewportEditorModesInterface* ViewportEditorModeTracker::GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const + const ViewportEditorModesInterface* ViewportEditorModeTracker::GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const { if (auto editorModeStates = m_viewportEditorModeStates.find(viewportEditorModeInfo.m_id); editorModeStates != m_viewportEditorModeStates.end()) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h index 23c02dbcdf..be090e6f1f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h @@ -51,7 +51,7 @@ namespace AzToolsFramework // ViewportEditorModeTrackerInterface ... void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; - const ViewportEditorModesInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; + const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; size_t GetNumTrackedViewports() const override; bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 5c9104ab18..e78f564c9d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -96,7 +96,7 @@ namespace AzToolsFramework viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModeStates, mode); } - const ViewportEditorModesInterface* ViewportEditorModeTracker::GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const + const ViewportEditorModesInterface* ViewportEditorModeTracker::GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const { if (auto editorModeStates = m_viewportEditorModeStates.find(viewportEditorModeInfo.m_id); editorModeStates != m_viewportEditorModeStates.end()) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h index 23c02dbcdf..be090e6f1f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h @@ -51,7 +51,7 @@ namespace AzToolsFramework // ViewportEditorModeTrackerInterface ... void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; - const ViewportEditorModesInterface* GetEditorModeState(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; + const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; size_t GetNumTrackedViewports() const override; bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 63f975acdc..d59e017579 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -291,12 +291,12 @@ namespace UnitTest // Given a viewport not currently being tracked const ViewportId viewportid = 0; EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); // When a mode is activated for that viewport const auto editorMode = ViewportEditorMode::Default; m_viewportEditorModeStteTracker.EnterMode({ viewportid }, editorMode); - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); // Expect that viewport to now be tracked EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); @@ -311,7 +311,7 @@ namespace UnitTest // Given a viewport not currently being tracked const ViewportId viewportid = 0; EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); // When a mode is deactivated for that viewport const auto editorMode = ViewportEditorMode::Default; @@ -323,7 +323,7 @@ namespace UnitTest EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); // Expect that viewport to now be tracked - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); // Expect the mode for that viewport to be inactive @@ -335,7 +335,7 @@ namespace UnitTest { const ViewportId viewportid = 0; EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); } TEST_F(ViewportEditorModeTrackerTestFixture, EnteringViewportEditorModesForExistingIdInThatStateIssuesWarningMsg) @@ -343,7 +343,7 @@ namespace UnitTest // Given a viewport not currently tracked const ViewportId viewportid = 0; EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); const auto editorMode = ViewportEditorMode::Default; const auto expectedWarning = AZStd::string::format( @@ -359,7 +359,7 @@ namespace UnitTest EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); // Expect the mode to be active for the viewport - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); @@ -373,7 +373,7 @@ namespace UnitTest EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); // Expect the mode to still be active for the viewport - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); @@ -385,7 +385,7 @@ namespace UnitTest // Given a viewport not currently tracked const ViewportId viewportid = 0; EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }), nullptr); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); const auto editorMode = ViewportEditorMode::Default; const auto expectedWarning = @@ -402,7 +402,7 @@ namespace UnitTest EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); // Expect the mode to be inctive for the viewport - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); @@ -417,7 +417,7 @@ namespace UnitTest EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); // Expect the mode to still be inactive for the viewport - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetEditorModeState({ viewportid }); + const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); From 3b47d9c5a659972759b3147ab38e313489ba14a9 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 14 Sep 2021 19:15:18 +0100 Subject: [PATCH 06/50] GetNumTrackedViewports -> GetTrackedViewportCount Signed-off-by: John --- .../API/ViewportEditorModeStateTrackerInterface.h | 2 +- .../AzToolsFramework/API/ViewportEditorModeTrackerInterface.h | 2 +- .../ViewportSelection/ViewportEditorModeStateTracker.cpp | 2 +- .../ViewportSelection/ViewportEditorModeStateTracker.h | 2 +- .../ViewportSelection/ViewportEditorModeTracker.cpp | 2 +- .../ViewportSelection/ViewportEditorModeTracker.h | 2 +- .../AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h index 706fd98c5e..7d51dd64a1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h @@ -31,7 +31,7 @@ namespace AzToolsFramework virtual const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; //! Returns the number of viewports currently being tracked. - virtual size_t GetNumTrackedViewports() const = 0; + virtual size_t GetTrackedViewportCount() const = 0; //! Returns true if the specified viewport is being tracked, otherwise false. virtual bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h index 706fd98c5e..7d51dd64a1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h @@ -31,7 +31,7 @@ namespace AzToolsFramework virtual const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; //! Returns the number of viewports currently being tracked. - virtual size_t GetNumTrackedViewports() const = 0; + virtual size_t GetTrackedViewportCount() const = 0; //! Returns true if the specified viewport is being tracked, otherwise false. virtual bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp index e78f564c9d..3d88d7d93e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp @@ -109,7 +109,7 @@ namespace AzToolsFramework } } - size_t ViewportEditorModeTracker::GetNumTrackedViewports() const + size_t ViewportEditorModeTracker::GetTrackedViewportCount() const { return m_viewportEditorModeStates.size(); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h index be090e6f1f..12a64cbbf9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h @@ -52,7 +52,7 @@ namespace AzToolsFramework void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; - size_t GetNumTrackedViewports() const override; + size_t GetTrackedViewportCount() const override; bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; private: diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index e78f564c9d..3d88d7d93e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -109,7 +109,7 @@ namespace AzToolsFramework } } - size_t ViewportEditorModeTracker::GetNumTrackedViewports() const + size_t ViewportEditorModeTracker::GetTrackedViewportCount() const { return m_viewportEditorModeStates.size(); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h index be090e6f1f..12a64cbbf9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h @@ -52,7 +52,7 @@ namespace AzToolsFramework void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; - size_t GetNumTrackedViewports() const override; + size_t GetTrackedViewportCount() const override; bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; private: diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index d59e017579..8e9b1ba59b 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -283,7 +283,7 @@ namespace UnitTest TEST_F(ViewportEditorModeTrackerTestFixture, InitialCentralStateTrackerHasNoViewportEditorModess) { - EXPECT_EQ(m_viewportEditorModeStteTracker.GetNumTrackedViewports(), 0); + EXPECT_EQ(m_viewportEditorModeStteTracker.GetTrackedViewportCount(), 0); } TEST_F(ViewportEditorModeTrackerTestFixture, EnteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) From 7960c68b487622f0e99ed8f0f7d72699276d85b5 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 14 Sep 2021 19:16:22 +0100 Subject: [PATCH 07/50] IsViewportStateBeingTracked -> IsViewportModeTracked Signed-off-by: John --- .../ViewportEditorModeStateTrackerInterface.h | 2 +- .../API/ViewportEditorModeTrackerInterface.h | 2 +- .../ViewportEditorModeStateTracker.cpp | 2 +- .../ViewportEditorModeStateTracker.h | 2 +- .../ViewportEditorModeTracker.cpp | 2 +- .../ViewportEditorModeTracker.h | 2 +- .../Viewport/ViewportEditorModeTests.cpp | 22 +++++++++---------- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h index 7d51dd64a1..53b0729bac 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h @@ -34,7 +34,7 @@ namespace AzToolsFramework virtual size_t GetTrackedViewportCount() const = 0; //! Returns true if the specified viewport is being tracked, otherwise false. - virtual bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; + virtual bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; private: }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h index 7d51dd64a1..53b0729bac 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h @@ -34,7 +34,7 @@ namespace AzToolsFramework virtual size_t GetTrackedViewportCount() const = 0; //! Returns true if the specified viewport is being tracked, otherwise false. - virtual bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; + virtual bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; private: }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp index 3d88d7d93e..2eb8cdb9d8 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp @@ -114,7 +114,7 @@ namespace AzToolsFramework return m_viewportEditorModeStates.size(); } - bool ViewportEditorModeTracker::IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const + bool ViewportEditorModeTracker::IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const { return m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id) > 0; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h index 12a64cbbf9..0ec5a31ddd 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h @@ -53,7 +53,7 @@ namespace AzToolsFramework void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; size_t GetTrackedViewportCount() const override; - bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; + bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; private: using ViewportEditorModess = AZStd::unordered_map; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 3d88d7d93e..2eb8cdb9d8 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -114,7 +114,7 @@ namespace AzToolsFramework return m_viewportEditorModeStates.size(); } - bool ViewportEditorModeTracker::IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const + bool ViewportEditorModeTracker::IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const { return m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id) > 0; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h index 12a64cbbf9..0ec5a31ddd 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h @@ -53,7 +53,7 @@ namespace AzToolsFramework void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; size_t GetTrackedViewportCount() const override; - bool IsViewportStateBeingTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; + bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; private: using ViewportEditorModess = AZStd::unordered_map; diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 8e9b1ba59b..7603f68b64 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -290,7 +290,7 @@ namespace UnitTest { // Given a viewport not currently being tracked const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); // When a mode is activated for that viewport @@ -299,7 +299,7 @@ namespace UnitTest const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); // Expect that viewport to now be tracked - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); // Expect the mode for that viewport to be active @@ -310,7 +310,7 @@ namespace UnitTest { // Given a viewport not currently being tracked const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); // When a mode is deactivated for that viewport @@ -324,7 +324,7 @@ namespace UnitTest // Expect that viewport to now be tracked const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); // Expect the mode for that viewport to be inactive EXPECT_NE(viewportEditorModeState, nullptr); @@ -334,7 +334,7 @@ namespace UnitTest TEST_F(ViewportEditorModeTrackerTestFixture, GettingNonExistentViewportEditorModesForIdReturnsNull) { const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); } @@ -342,7 +342,7 @@ namespace UnitTest { // Given a viewport not currently tracked const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); const auto editorMode = ViewportEditorMode::Default; @@ -360,7 +360,7 @@ namespace UnitTest // Expect the mode to be active for the viewport const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } @@ -374,7 +374,7 @@ namespace UnitTest // Expect the mode to still be active for the viewport const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } @@ -384,7 +384,7 @@ namespace UnitTest { // Given a viewport not currently tracked const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); const auto editorMode = ViewportEditorMode::Default; @@ -403,7 +403,7 @@ namespace UnitTest // Expect the mode to be inctive for the viewport const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); } @@ -418,7 +418,7 @@ namespace UnitTest // Expect the mode to still be inactive for the viewport const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportStateBeingTracked({ viewportid })); + EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); } From 9dfc91cb77ad66c7a3c79135d7f8d43cd3d11330 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 14 Sep 2021 19:26:50 +0100 Subject: [PATCH 08/50] Fix API comments. Signed-off-by: John --- ...ViewportEditorModeTrackerNotificationBus.h | 5 +-- .../EditorInteractionInterface.h | 33 ------------------- 2 files changed, 3 insertions(+), 35 deletions(-) delete mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionInterface.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h index b9b5c80f39..cdb50e30e7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h @@ -5,6 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once #include @@ -13,7 +14,7 @@ namespace AzToolsFramework { - //! Enumeration of each viewport editor state. + //! Enumeration of each viewport editor mode. enum class ViewportEditorMode : AZ::u8 { Default, @@ -62,4 +63,4 @@ namespace AzToolsFramework } }; using ViewportEditorModeNotificationsBus = AZ::EBus; -} +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionInterface.h deleted file mode 100644 index 70cbfd09ec..0000000000 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionInterface.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include - -namespace AzToolsFramework -{ - /*! - * EditorInteractionInterface - * Allows systems to alter the behavior of viewport selection. - */ - class EditorInteractionInterface - { - public: - AZ_RTTI(EditorInteractionInterface, "{09276E3C-9AA6-40FF-A0B5-3D33A33F0E5A}"); - - /*! - * Allows the entity system to redirect the selection of an entity to another entity. - * It can be used to select a container when clicking on its content. - */ - virtual AZ::EntityId RedirectEntitySelection(AZ::EntityId entityId) = 0; - }; - -} // namespace AzToolsFramework - From 82fbbb79664be8a4054d0d48752e20ab34f866eb Mon Sep 17 00:00:00 2001 From: John Date: Wed, 15 Sep 2021 08:53:59 +0100 Subject: [PATCH 09/50] Delete hangover file. Signed-off-by: John --- .../ViewportEditorModeStateTrackerInterface.h | 42 ------------------- 1 file changed, 42 deletions(-) delete mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h deleted file mode 100644 index 53b0729bac..0000000000 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeStateTrackerInterface.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include - -namespace AzToolsFramework -{ - //! The AZ::Interface of the central editor mode state tracker for all viewports. - class ViewportEditorModeTrackerInterface - { - public: - AZ_RTTI(ViewportEditorModeTrackerInterface, "{7D72A4F7-2147-4ED9-A315-E456A3BE3CF6}"); - - virtual ~ViewportEditorModeTrackerInterface() = default; - - //! Enters the specified editor mode for the specified viewport. - virtual void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; - - //! Exits the specified editor mode for the specified viewport. - virtual void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; - - //! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr. - virtual const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; - - //! Returns the number of viewports currently being tracked. - virtual size_t GetTrackedViewportCount() const = 0; - - //! Returns true if the specified viewport is being tracked, otherwise false. - virtual bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; - - private: - }; -} // namespace AzToolsFramework - From 00497ad9959694ee48c6dfdb6ace16da3cd2bdad Mon Sep 17 00:00:00 2001 From: John Date: Wed, 15 Sep 2021 09:05:56 +0100 Subject: [PATCH 10/50] Delete more hangover files. Signed-off-by: John --- .../ViewportEditorModeStateTracker.cpp | 121 ------------------ .../ViewportEditorModeStateTracker.h | 62 --------- 2 files changed, 183 deletions(-) delete mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp delete mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp deleted file mode 100644 index 2eb8cdb9d8..0000000000 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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 -#include - -namespace AzToolsFramework -{ - static constexpr const char* ViewportEditorModeLogWindow = "ViewportEditorMode"; - - void ViewportEditorModes::SetModeActive(ViewportEditorMode mode) - { - if (const AZ::u32 modeIndex = static_cast(mode); - modeIndex < NumEditorModes) - { - m_editorModes[modeIndex] = true; - } - else - { - AZ_Error(ViewportEditorModeLogWindow, false, "Cannot activate mode %u, mode is not recognized", modeIndex) - } - } - - void ViewportEditorModes::SetModeInactive(ViewportEditorMode mode) - { - if (const AZ::u32 modeIndex = static_cast(mode); modeIndex < NumEditorModes) - { - m_editorModes[modeIndex] = false; - } - else - { - AZ_Error(ViewportEditorModeLogWindow, false, "Cannot deactivate mode %u, mode is not recognized", modeIndex) - } - } - - bool ViewportEditorModes::IsModeActive(ViewportEditorMode mode) const - { - return m_editorModes[static_cast(mode)]; - } - - void ViewportEditorModeTracker::RegisterInterface() - { - if (AZ::Interface::Get() == nullptr) - { - AZ::Interface::Register(this); - } - } - - void ViewportEditorModeTracker::UnregisterInterface() - { - if (AZ::Interface::Get() != nullptr) - { - AZ::Interface::Unregister(this); - } - } - - void ViewportEditorModeTracker::EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) - { - auto& editorModeStates = m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; - AZ_Warning( - ViewportEditorModeLogWindow, !editorModeStates.IsModeActive(mode), - AZStd::string::format( - "Duplicate call to EnterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); - editorModeStates.SetModeActive(mode); - ViewportEditorModeNotificationsBus::Event( - viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModeStates, mode); - } - - void ViewportEditorModeTracker::ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) - { - ViewportEditorModes* editorModeStates = nullptr; - if (m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id)) - { - editorModeStates = &m_viewportEditorModeStates.at(viewportEditorModeInfo.m_id); - AZ_Warning( - ViewportEditorModeLogWindow, editorModeStates->IsModeActive(mode), - AZStd::string::format( - "Duplicate call to ExitMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); - } - else - { - AZ_Warning( - ViewportEditorModeLogWindow, false, "Call to ExitMode for mode '%u' on id '%i' without precursor call to EnterMode", - static_cast(mode), viewportEditorModeInfo.m_id); - - editorModeStates = &m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; - } - - editorModeStates->SetModeInactive(mode); - ViewportEditorModeNotificationsBus::Event( - viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModeStates, mode); - } - - const ViewportEditorModesInterface* ViewportEditorModeTracker::GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const - { - if (auto editorModeStates = m_viewportEditorModeStates.find(viewportEditorModeInfo.m_id); - editorModeStates != m_viewportEditorModeStates.end()) - { - return &editorModeStates->second; - } - else - { - return nullptr; - } - } - - size_t ViewportEditorModeTracker::GetTrackedViewportCount() const - { - return m_viewportEditorModeStates.size(); - } - - bool ViewportEditorModeTracker::IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const - { - return m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id) > 0; - } -} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h deleted file mode 100644 index 0ec5a31ddd..0000000000 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeStateTracker.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include -#include -#include -#include - -namespace AzToolsFramework -{ - //! The encapsulation of the editor modes for a given viewport. - class ViewportEditorModes - : public ViewportEditorModesInterface - { - public: - - //! The number of currently supported viewport editor modes. - static constexpr AZ::u8 NumEditorModes = 4; - - //! Sets the specified mode as active. - void SetModeActive(ViewportEditorMode mode); - - // Sets the specified mode as inactive. - void SetModeInactive(ViewportEditorMode mode); - - // ViewportEditorModesInterface ... - bool IsModeActive(ViewportEditorMode mode) const override; - private: - AZStd::array m_editorModes{}; //!< State flags to track active/inactive status of viewport editor modes. - }; - - //! The implementation of the central editor mode state tracker for all viewports. - class ViewportEditorModeTracker - : public ViewportEditorModeTrackerInterface - { - public: - //! Registers this object with the AZ::Interface. - void RegisterInterface(); - - //! Unregisters this object with the AZ::Interface. - void UnregisterInterface(); - - // ViewportEditorModeTrackerInterface ... - void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; - void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; - const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; - size_t GetTrackedViewportCount() const override; - bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; - - private: - using ViewportEditorModess = AZStd::unordered_map; - ViewportEditorModess m_viewportEditorModeStates; //!< Editor mode state per viewport. - }; -} // namespace AzToolsFramework From 66f78889e656a2569a3d3c36663bb2714f2faeec Mon Sep 17 00:00:00 2001 From: John Date: Wed, 15 Sep 2021 09:26:16 +0100 Subject: [PATCH 11/50] Minor member name refactor. Signed-off-by: John --- .../Viewport/ViewportEditorModeTests.cpp | 110 +++++++++--------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 7603f68b64..7eb4f68d87 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -40,7 +40,7 @@ namespace UnitTest : public ::testing::Test { public: - ViewportEditorModes m_editorModeState; + ViewportEditorModes m_editorModes; }; // Fixture for testing editor mode states with parameterized test arguments @@ -62,7 +62,7 @@ namespace UnitTest : public ToolsApplicationFixture { public: - ViewportEditorModeTracker m_viewportEditorModeStteTracker; + ViewportEditorModeTracker m_viewportEditorModeTracker; }; // Subscriber of viewport editor mode notifications for a single viewport that expects a single mode to be activated/deactivated @@ -149,43 +149,43 @@ namespace UnitTest { for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { - EXPECT_FALSE(m_editorModeState.IsModeActive(static_cast(mode))); + EXPECT_FALSE(m_editorModes.IsModeActive(static_cast(mode))); } } TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeActiveActivatesOnlyThatMode) { - m_editorModeState.SetModeActive(m_selectedEditorMode); + m_editorModes.SetModeActive(m_selectedEditorMode); for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { const auto editorMode = static_cast(mode); if (editorMode == m_selectedEditorMode) { - EXPECT_TRUE(m_editorModeState.IsModeActive(static_cast(editorMode))); + EXPECT_TRUE(m_editorModes.IsModeActive(static_cast(editorMode))); } else { - EXPECT_FALSE(m_editorModeState.IsModeActive(static_cast(editorMode))); + EXPECT_FALSE(m_editorModes.IsModeActive(static_cast(editorMode))); } } } TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeInactiveInactivatesOnlyThatMode) { - SetAllModesActive(m_editorModeState); - m_editorModeState.SetModeInactive(m_selectedEditorMode); + SetAllModesActive(m_editorModes); + m_editorModes.SetModeInactive(m_selectedEditorMode); for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { const auto editorMode = static_cast(mode); if (editorMode == m_selectedEditorMode) { - EXPECT_FALSE(m_editorModeState.IsModeActive(editorMode)); + EXPECT_FALSE(m_editorModes.IsModeActive(editorMode)); } else { - EXPECT_TRUE(m_editorModeState.IsModeActive(editorMode)); + EXPECT_TRUE(m_editorModes.IsModeActive(editorMode)); } } } @@ -195,8 +195,8 @@ namespace UnitTest for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes - 1; mode++) { // Given only the selected mode active - SetAllModesInactive(m_editorModeState); - m_editorModeState.SetModeActive(m_selectedEditorMode); + SetAllModesInactive(m_editorModes); + m_editorModes.SetModeActive(m_selectedEditorMode); const auto editorMode = static_cast(mode); if (editorMode == m_selectedEditorMode) @@ -205,7 +205,7 @@ namespace UnitTest } // When other modes are activated - m_editorModeState.SetModeActive(editorMode); + m_editorModes.SetModeActive(editorMode); for (auto expectedMode = 0; expectedMode < ViewportEditorModes::NumEditorModes; expectedMode++) { @@ -213,12 +213,12 @@ namespace UnitTest if (expectedEditorMode == editorMode || expectedEditorMode == m_selectedEditorMode) { // Expect the activated modes to be active - EXPECT_TRUE(m_editorModeState.IsModeActive(expectedEditorMode)); + EXPECT_TRUE(m_editorModes.IsModeActive(expectedEditorMode)); } else { // Expect the modes not active to be inactive - EXPECT_FALSE(m_editorModeState.IsModeActive(expectedEditorMode)); + EXPECT_FALSE(m_editorModes.IsModeActive(expectedEditorMode)); } } } @@ -229,8 +229,8 @@ namespace UnitTest for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes - 1; mode++) { // Given only the selected mode inactive - SetAllModesActive(m_editorModeState); - m_editorModeState.SetModeInactive(m_selectedEditorMode); + SetAllModesActive(m_editorModes); + m_editorModes.SetModeInactive(m_selectedEditorMode); const auto editorMode = static_cast(mode); if (editorMode == m_selectedEditorMode) @@ -239,7 +239,7 @@ namespace UnitTest } // When other modes are deactivated - m_editorModeState.SetModeInactive(editorMode); + m_editorModes.SetModeInactive(editorMode); for (auto expectedMode = 0; expectedMode < ViewportEditorModes::NumEditorModes; expectedMode++) { @@ -247,12 +247,12 @@ namespace UnitTest if (expectedEditorMode == editorMode || expectedEditorMode == m_selectedEditorMode) { // Expect the deactivated modes to be inactive - EXPECT_FALSE(m_editorModeState.IsModeActive(expectedEditorMode)); + EXPECT_FALSE(m_editorModes.IsModeActive(expectedEditorMode)); } else { // Expects the modes not deactivated to still be active - EXPECT_TRUE(m_editorModeState.IsModeActive(expectedEditorMode)); + EXPECT_TRUE(m_editorModes.IsModeActive(expectedEditorMode)); } } } @@ -270,36 +270,36 @@ namespace UnitTest TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeActiveIssuesErrorMsg) { UnitTest::TestRunner::Instance().StartAssertTests(); - m_editorModeState.SetModeActive(static_cast(ViewportEditorModes::NumEditorModes)); + m_editorModes.SetModeActive(static_cast(ViewportEditorModes::NumEditorModes)); EXPECT_EQ(1, UnitTest::TestRunner::Instance().StopAssertTests()); } TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeInactiveIssuesErrorMsg) { UnitTest::TestRunner::Instance().StartAssertTests(); - m_editorModeState.SetModeInactive(static_cast(ViewportEditorModes::NumEditorModes)); + m_editorModes.SetModeInactive(static_cast(ViewportEditorModes::NumEditorModes)); EXPECT_EQ(1, UnitTest::TestRunner::Instance().StopAssertTests()); } TEST_F(ViewportEditorModeTrackerTestFixture, InitialCentralStateTrackerHasNoViewportEditorModess) { - EXPECT_EQ(m_viewportEditorModeStteTracker.GetTrackedViewportCount(), 0); + EXPECT_EQ(m_viewportEditorModeTracker.GetTrackedViewportCount(), 0); } TEST_F(ViewportEditorModeTrackerTestFixture, EnteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); + EXPECT_FALSE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); // When a mode is activated for that viewport const auto editorMode = ViewportEditorMode::Default; - m_viewportEditorModeStteTracker.EnterMode({ viewportid }, editorMode); - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); + m_viewportEditorModeTracker.EnterMode({ viewportid }, editorMode); + const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); // Expect that viewport to now be tracked - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); + EXPECT_TRUE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); // Expect the mode for that viewport to be active @@ -310,21 +310,21 @@ namespace UnitTest { // Given a viewport not currently being tracked const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); + EXPECT_FALSE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); // When a mode is deactivated for that viewport const auto editorMode = ViewportEditorMode::Default; UnitTest::ErrorHandler errorHandler(AZStd::string::format( "Call to ExitMode for mode '%u' on id '%i' without precursor call to EnterMode", static_cast(editorMode), viewportid).c_str()); - m_viewportEditorModeStteTracker.ExitMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.ExitMode({ viewportid }, editorMode); // Expect a warning to be issued due to no precursor activation of that mode EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); // Expect that viewport to now be tracked - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); + const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); // Expect the mode for that viewport to be inactive EXPECT_NE(viewportEditorModeState, nullptr); @@ -334,16 +334,16 @@ namespace UnitTest TEST_F(ViewportEditorModeTrackerTestFixture, GettingNonExistentViewportEditorModesForIdReturnsNull) { const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); + EXPECT_FALSE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); } TEST_F(ViewportEditorModeTrackerTestFixture, EnteringViewportEditorModesForExistingIdInThatStateIssuesWarningMsg) { // Given a viewport not currently tracked const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); + EXPECT_FALSE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); const auto editorMode = ViewportEditorMode::Default; const auto expectedWarning = AZStd::string::format( @@ -353,28 +353,28 @@ namespace UnitTest UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); // When the mode is activated for the viewport - m_viewportEditorModeStteTracker.EnterMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.EnterMode({ viewportid }, editorMode); // Expect no warning to be issued as there is no duplicate activation EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); // Expect the mode to be active for the viewport - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); + const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } { // When the mode is activated again for the viewport UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); - m_viewportEditorModeStteTracker.EnterMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.EnterMode({ viewportid }, editorMode); // Expect a warning to be issued for the duplicate activation EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); // Expect the mode to still be active for the viewport - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); + const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } @@ -384,8 +384,8 @@ namespace UnitTest { // Given a viewport not currently tracked const ViewportId viewportid = 0; - EXPECT_FALSE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); - EXPECT_EQ(m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }), nullptr); + EXPECT_FALSE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); + EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); const auto editorMode = ViewportEditorMode::Default; const auto expectedWarning = @@ -395,15 +395,15 @@ namespace UnitTest UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); // When the mode is activated and then deactivated for the viewport - m_viewportEditorModeStteTracker.EnterMode({ viewportid }, editorMode); - m_viewportEditorModeStteTracker.ExitMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.EnterMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.ExitMode({ viewportid }, editorMode); // Expect no warning to be issued as there is no duplicate deactivation EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); // Expect the mode to be inctive for the viewport - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); + const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); } @@ -411,14 +411,14 @@ namespace UnitTest UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); // When the mode is deactivated again for the viewport - m_viewportEditorModeStteTracker.ExitMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.ExitMode({ viewportid }, editorMode); // Expect a warning to be issued for the duplicate deactivation EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); // Expect the mode to still be inactive for the viewport - const auto* viewportEditorModeState = m_viewportEditorModeStteTracker.GetViewportEditorModes({ viewportid }); - EXPECT_TRUE(m_viewportEditorModeStteTracker.IsViewportModeTracked({ viewportid })); + const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); + EXPECT_TRUE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid })); EXPECT_NE(viewportEditorModeState, nullptr); EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); } @@ -440,7 +440,7 @@ namespace UnitTest { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); - m_viewportEditorModeStteTracker.EnterMode({ mode }, editorMode); + m_viewportEditorModeTracker.EnterMode({ mode }, editorMode); } for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -472,8 +472,8 @@ namespace UnitTest { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); - m_viewportEditorModeStteTracker.EnterMode({ mode }, editorMode); - m_viewportEditorModeStteTracker.ExitMode({ mode }, editorMode); + m_viewportEditorModeTracker.EnterMode({ mode }, editorMode); + m_viewportEditorModeTracker.ExitMode({ mode }, editorMode); } for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) From 15ae8c2c064d6f43c3a1da7877e4973ebef4bbb9 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 15 Sep 2021 11:00:59 +0100 Subject: [PATCH 12/50] Refactor nonclemanture. Signed-off-by: John --- .../API/ViewportEditorModeTrackerInterface.h | 4 +-- ...ViewportEditorModeTrackerNotificationBus.h | 2 +- .../ViewportEditorModeTracker.cpp | 32 +++++++++---------- .../ViewportEditorModeTracker.h | 4 +-- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h index 53b0729bac..4bafdc3d01 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h @@ -13,7 +13,7 @@ namespace AzToolsFramework { - //! The AZ::Interface of the central editor mode state tracker for all viewports. + //! The AZ::Interface of the central editor mode tracker for all viewports. class ViewportEditorModeTrackerInterface { public: @@ -35,8 +35,6 @@ namespace AzToolsFramework //! Returns true if the specified viewport is being tracked, otherwise false. virtual bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; - - private: }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h index cdb50e30e7..caa762241c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h @@ -30,7 +30,7 @@ namespace AzToolsFramework IdType m_id = ViewportUi::DefaultViewportId; //!< The unique identifier for a given viewport. }; - //! Interface for the editor mode state of a given viewport. + //! Interface for the editor modes of a given viewport. class ViewportEditorModesInterface { public: diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 2eb8cdb9d8..511024daed 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -61,24 +61,24 @@ namespace AzToolsFramework void ViewportEditorModeTracker::EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { - auto& editorModeStates = m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; + auto& editorModes = m_viewportEditorModesMap[viewportEditorModeInfo.m_id]; AZ_Warning( - ViewportEditorModeLogWindow, !editorModeStates.IsModeActive(mode), + ViewportEditorModeLogWindow, !editorModes.IsModeActive(mode), AZStd::string::format( "Duplicate call to EnterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); - editorModeStates.SetModeActive(mode); + editorModes.SetModeActive(mode); ViewportEditorModeNotificationsBus::Event( - viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModeStates, mode); + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModes, mode); } void ViewportEditorModeTracker::ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { - ViewportEditorModes* editorModeStates = nullptr; - if (m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id)) + ViewportEditorModes* editorModes = nullptr; + if (m_viewportEditorModesMap.count(viewportEditorModeInfo.m_id)) { - editorModeStates = &m_viewportEditorModeStates.at(viewportEditorModeInfo.m_id); + editorModes = &m_viewportEditorModesMap.at(viewportEditorModeInfo.m_id); AZ_Warning( - ViewportEditorModeLogWindow, editorModeStates->IsModeActive(mode), + ViewportEditorModeLogWindow, editorModes->IsModeActive(mode), AZStd::string::format( "Duplicate call to ExitMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); } @@ -88,20 +88,20 @@ namespace AzToolsFramework ViewportEditorModeLogWindow, false, "Call to ExitMode for mode '%u' on id '%i' without precursor call to EnterMode", static_cast(mode), viewportEditorModeInfo.m_id); - editorModeStates = &m_viewportEditorModeStates[viewportEditorModeInfo.m_id]; + editorModes = &m_viewportEditorModesMap[viewportEditorModeInfo.m_id]; } - editorModeStates->SetModeInactive(mode); + editorModes->SetModeInactive(mode); ViewportEditorModeNotificationsBus::Event( - viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModeStates, mode); + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModes, mode); } const ViewportEditorModesInterface* ViewportEditorModeTracker::GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const { - if (auto editorModeStates = m_viewportEditorModeStates.find(viewportEditorModeInfo.m_id); - editorModeStates != m_viewportEditorModeStates.end()) + if (auto editorModes = m_viewportEditorModesMap.find(viewportEditorModeInfo.m_id); + editorModes != m_viewportEditorModesMap.end()) { - return &editorModeStates->second; + return &editorModes->second; } else { @@ -111,11 +111,11 @@ namespace AzToolsFramework size_t ViewportEditorModeTracker::GetTrackedViewportCount() const { - return m_viewportEditorModeStates.size(); + return m_viewportEditorModesMap.size(); } bool ViewportEditorModeTracker::IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const { - return m_viewportEditorModeStates.count(viewportEditorModeInfo.m_id) > 0; + return m_viewportEditorModesMap.count(viewportEditorModeInfo.m_id) > 0; } } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h index 0ec5a31ddd..222e5af829 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h @@ -56,7 +56,7 @@ namespace AzToolsFramework bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; private: - using ViewportEditorModess = AZStd::unordered_map; - ViewportEditorModess m_viewportEditorModeStates; //!< Editor mode state per viewport. + using ViewportEditorModesMap = AZStd::unordered_map; + ViewportEditorModesMap m_viewportEditorModesMap; //!< Editor mode state per viewport. }; } // namespace AzToolsFramework From c713077e070e0109254a4abb6bacc881eef01df5 Mon Sep 17 00:00:00 2001 From: John Date: Fri, 17 Sep 2021 17:02:28 +0100 Subject: [PATCH 13/50] Rename Enter/ExitMode to Register/UnregisterMode. Signed-off-by: John --- .../API/ViewportEditorModeTrackerInterface.h | 8 ++-- .../ViewportEditorModeTracker.cpp | 10 ++-- .../ViewportEditorModeTracker.h | 6 +-- .../Viewport/ViewportEditorModeTests.cpp | 46 +++++++++---------- 4 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h index 4bafdc3d01..062d326046 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h @@ -21,11 +21,11 @@ namespace AzToolsFramework virtual ~ViewportEditorModeTrackerInterface() = default; - //! Enters the specified editor mode for the specified viewport. - virtual void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; + //! Registers the specified editor mode as active for the specified viewport. + virtual void RegisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; - //! Exits the specified editor mode for the specified viewport. - virtual void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; + //! Unregisters the specified editor mode as active for the specified viewport. + virtual void UnregisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; //! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr. virtual const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 511024daed..1dfc4ac035 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -59,19 +59,19 @@ namespace AzToolsFramework } } - void ViewportEditorModeTracker::EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + void ViewportEditorModeTracker::RegisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { auto& editorModes = m_viewportEditorModesMap[viewportEditorModeInfo.m_id]; AZ_Warning( ViewportEditorModeLogWindow, !editorModes.IsModeActive(mode), AZStd::string::format( - "Duplicate call to EnterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); + "Duplicate call to RegisterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); editorModes.SetModeActive(mode); ViewportEditorModeNotificationsBus::Event( viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModes, mode); } - void ViewportEditorModeTracker::ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + void ViewportEditorModeTracker::UnregisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { ViewportEditorModes* editorModes = nullptr; if (m_viewportEditorModesMap.count(viewportEditorModeInfo.m_id)) @@ -80,12 +80,12 @@ namespace AzToolsFramework AZ_Warning( ViewportEditorModeLogWindow, editorModes->IsModeActive(mode), AZStd::string::format( - "Duplicate call to ExitMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); + "Duplicate call to UnregisterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); } else { AZ_Warning( - ViewportEditorModeLogWindow, false, "Call to ExitMode for mode '%u' on id '%i' without precursor call to EnterMode", + ViewportEditorModeLogWindow, false, "Call to UnregisterMode for mode '%u' on id '%i' without precursor call to RegisterMode", static_cast(mode), viewportEditorModeInfo.m_id); editorModes = &m_viewportEditorModesMap[viewportEditorModeInfo.m_id]; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h index 222e5af829..e766bd29b9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h @@ -48,9 +48,9 @@ namespace AzToolsFramework //! Unregisters this object with the AZ::Interface. void UnregisterInterface(); - // ViewportEditorModeTrackerInterface ... - void EnterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; - void ExitMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + // ViewportEditorModeTrackerInterface overrides ... + void RegisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + void UnregisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; size_t GetTrackedViewportCount() const override; bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 7eb4f68d87..ac61a20bf6 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -73,7 +73,7 @@ namespace UnitTest struct ReceivedEvents { bool m_onEnter = false; - bool m_onLeave = false; + bool m_onExit = false; }; using EditModeTracker = AZStd::unordered_map; @@ -106,7 +106,7 @@ namespace UnitTest virtual void OnEditorModeExit([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override { - m_editorModes[mode].m_onLeave = true; + m_editorModes[mode].m_onExit = true; } private: @@ -286,7 +286,7 @@ namespace UnitTest EXPECT_EQ(m_viewportEditorModeTracker.GetTrackedViewportCount(), 0); } - TEST_F(ViewportEditorModeTrackerTestFixture, EnteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) + TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -295,7 +295,7 @@ namespace UnitTest // When a mode is activated for that viewport const auto editorMode = ViewportEditorMode::Default; - m_viewportEditorModeTracker.EnterMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); // Expect that viewport to now be tracked @@ -306,7 +306,7 @@ namespace UnitTest EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } - TEST_F(ViewportEditorModeTrackerTestFixture, ExitingViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButIssuesErrorMsg) + TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButIssuesErrorMsg) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -316,8 +316,8 @@ namespace UnitTest // When a mode is deactivated for that viewport const auto editorMode = ViewportEditorMode::Default; UnitTest::ErrorHandler errorHandler(AZStd::string::format( - "Call to ExitMode for mode '%u' on id '%i' without precursor call to EnterMode", static_cast(editorMode), viewportid).c_str()); - m_viewportEditorModeTracker.ExitMode({ viewportid }, editorMode); + "Call to UnregisterMode for mode '%u' on id '%i' without precursor call to RegisterMode", static_cast(editorMode), viewportid).c_str()); + m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); // Expect a warning to be issued due to no precursor activation of that mode EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); @@ -338,7 +338,7 @@ namespace UnitTest EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); } - TEST_F(ViewportEditorModeTrackerTestFixture, EnteringViewportEditorModesForExistingIdInThatStateIssuesWarningMsg) + TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModesForExistingIdInThatStateIssuesWarningMsg) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -347,13 +347,13 @@ namespace UnitTest const auto editorMode = ViewportEditorMode::Default; const auto expectedWarning = AZStd::string::format( - "Duplicate call to EnterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); + "Duplicate call to RegisterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); { UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); // When the mode is activated for the viewport - m_viewportEditorModeTracker.EnterMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); // Expect no warning to be issued as there is no duplicate activation EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); @@ -367,7 +367,7 @@ namespace UnitTest { // When the mode is activated again for the viewport UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); - m_viewportEditorModeTracker.EnterMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); // Expect a warning to be issued for the duplicate activation EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); @@ -380,7 +380,7 @@ namespace UnitTest } } - TEST_F(ViewportEditorModeTrackerTestFixture, ExitingViewportEditorModesForExistingIdNotInThatStateIssuesWarningMsg) + TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModesForExistingIdNotInThatStateIssuesWarningMsg) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -389,14 +389,14 @@ namespace UnitTest const auto editorMode = ViewportEditorMode::Default; const auto expectedWarning = - AZStd::string::format("Duplicate call to ExitMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); + AZStd::string::format("Duplicate call to UnregisterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); { UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); // When the mode is activated and then deactivated for the viewport - m_viewportEditorModeTracker.EnterMode({ viewportid }, editorMode); - m_viewportEditorModeTracker.ExitMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); // Expect no warning to be issued as there is no duplicate deactivation EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); @@ -411,7 +411,7 @@ namespace UnitTest UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); // When the mode is deactivated again for the viewport - m_viewportEditorModeTracker.ExitMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); // Expect a warning to be issued for the duplicate deactivation EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); @@ -426,7 +426,7 @@ namespace UnitTest TEST_F( ViewportEditorModePublisherTestFixture, - EnteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeEnterEventForAllSubscribers) + RegisteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeRegisterEventForAllSubscribers) { // Given a set of subscribers tracking the editor modes for their exclusive viewport for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -440,7 +440,7 @@ namespace UnitTest { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); - m_viewportEditorModeTracker.EnterMode({ mode }, editorMode); + m_viewportEditorModeTracker.RegisterMode({ mode }, editorMode); } for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -453,13 +453,13 @@ namespace UnitTest const auto& expectedEditorModeSet = editorModes.find(editorMode); EXPECT_NE(expectedEditorModeSet, editorModes.end()); EXPECT_TRUE(expectedEditorModeSet->second.m_onEnter); - EXPECT_FALSE(expectedEditorModeSet->second.m_onLeave); + EXPECT_FALSE(expectedEditorModeSet->second.m_onExit); } } TEST_F( ViewportEditorModePublisherTestFixture, - ExitingViewportEditorModesForExistingIdPublishesOnViewportEditorModeExitEventForAllSubscribers) + UnregisteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeUnregisterEventForAllSubscribers) { // Given a set of subscribers tracking the editor modes for their exclusive viewport for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -472,8 +472,8 @@ namespace UnitTest { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); - m_viewportEditorModeTracker.EnterMode({ mode }, editorMode); - m_viewportEditorModeTracker.ExitMode({ mode }, editorMode); + m_viewportEditorModeTracker.RegisterMode({ mode }, editorMode); + m_viewportEditorModeTracker.UnregisterMode({ mode }, editorMode); } for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -486,7 +486,7 @@ namespace UnitTest const auto& expectedEditorModeSet = editorModes.find(editorMode); EXPECT_NE(expectedEditorModeSet, editorModes.end()); EXPECT_TRUE(expectedEditorModeSet->second.m_onEnter); - EXPECT_TRUE(expectedEditorModeSet->second.m_onLeave); + EXPECT_TRUE(expectedEditorModeSet->second.m_onExit); } } } // namespace UnitTest From 0c79bbd7800c49b01ca9cc8051d5dfb63b2cb9f8 Mon Sep 17 00:00:00 2001 From: John Date: Fri, 17 Sep 2021 17:38:45 +0100 Subject: [PATCH 14/50] Error and warning msgs now return AZ::Outcomes. Signed-off-by: John --- .../API/ViewportEditorModeTrackerInterface.h | 7 +- .../ViewportEditorModeTracker.cpp | 70 ++++++++---- .../ViewportEditorModeTracker.h | 8 +- .../Viewport/ViewportEditorModeTests.cpp | 104 +++++++++--------- 4 files changed, 114 insertions(+), 75 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h index 062d326046..ae4f3424eb 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include namespace AzToolsFramework @@ -22,10 +23,12 @@ namespace AzToolsFramework virtual ~ViewportEditorModeTrackerInterface() = default; //! Registers the specified editor mode as active for the specified viewport. - virtual void RegisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; + virtual AZ::Outcome RegisterMode( + const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; //! Unregisters the specified editor mode as active for the specified viewport. - virtual void UnregisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; + virtual AZ::Outcome UnregisterMode( + const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; //! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr. virtual const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 1dfc4ac035..36c1b09be7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -13,28 +13,32 @@ namespace AzToolsFramework { static constexpr const char* ViewportEditorModeLogWindow = "ViewportEditorMode"; - void ViewportEditorModes::SetModeActive(ViewportEditorMode mode) + AZ::Outcome ViewportEditorModes::SetModeActive(ViewportEditorMode mode) { if (const AZ::u32 modeIndex = static_cast(mode); modeIndex < NumEditorModes) { m_editorModes[modeIndex] = true; + return AZ::Success(); } else { - AZ_Error(ViewportEditorModeLogWindow, false, "Cannot activate mode %u, mode is not recognized", modeIndex) + return AZ::Failure( + AZStd::string::format(ViewportEditorModeLogWindow, false, "Cannot activate mode %u, mode is not recognized", modeIndex)); } } - void ViewportEditorModes::SetModeInactive(ViewportEditorMode mode) + AZ::Outcome ViewportEditorModes::SetModeInactive(ViewportEditorMode mode) { if (const AZ::u32 modeIndex = static_cast(mode); modeIndex < NumEditorModes) { m_editorModes[modeIndex] = false; + return AZ::Success(); } else { - AZ_Error(ViewportEditorModeLogWindow, false, "Cannot deactivate mode %u, mode is not recognized", modeIndex) + return AZ::Failure( + AZStd::string::format(ViewportEditorModeLogWindow, false, "Cannot deactivate mode %u, mode is not recognized", modeIndex)); } } @@ -59,41 +63,67 @@ namespace AzToolsFramework } } - void ViewportEditorModeTracker::RegisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + AZ::Outcome ViewportEditorModeTracker::RegisterMode( + const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { auto& editorModes = m_viewportEditorModesMap[viewportEditorModeInfo.m_id]; - AZ_Warning( - ViewportEditorModeLogWindow, !editorModes.IsModeActive(mode), - AZStd::string::format( - "Duplicate call to RegisterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); - editorModes.SetModeActive(mode); + if (editorModes.IsModeActive(mode)) + { + return AZ::Failure(AZStd::string::format( + "Duplicate call to RegisterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id)); + } + + if (const auto result = editorModes.SetModeActive(mode); + !result.IsSuccess()) + { + return result; + } + ViewportEditorModeNotificationsBus::Event( viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModes, mode); + + return AZ::Success(); } - void ViewportEditorModeTracker::UnregisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) + AZ::Outcome ViewportEditorModeTracker::UnregisterMode( + const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { ViewportEditorModes* editorModes = nullptr; + bool modeWasActive = true; if (m_viewportEditorModesMap.count(viewportEditorModeInfo.m_id)) { editorModes = &m_viewportEditorModesMap.at(viewportEditorModeInfo.m_id); - AZ_Warning( - ViewportEditorModeLogWindow, editorModes->IsModeActive(mode), - AZStd::string::format( - "Duplicate call to UnregisterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id).c_str()); + if (!editorModes->IsModeActive(mode)) + { + return AZ::Failure(AZStd::string::format( + "Duplicate call to UnregisterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id)); + } } else { - AZ_Warning( - ViewportEditorModeLogWindow, false, "Call to UnregisterMode for mode '%u' on id '%i' without precursor call to RegisterMode", - static_cast(mode), viewportEditorModeInfo.m_id); - + modeWasActive = false; editorModes = &m_viewportEditorModesMap[viewportEditorModeInfo.m_id]; } - editorModes->SetModeInactive(mode); + if(const auto result = editorModes->SetModeInactive(mode); + !result.IsSuccess()) + { + return result; + } + ViewportEditorModeNotificationsBus::Event( viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModes, mode); + + if (modeWasActive) + { + return AZ::Success(); + } + else + { + return AZ::Failure(AZStd::string::format( + "Call to UnregisterMode for mode '%u' on id '%i' without precursor call to RegisterMode", static_cast(mode), + viewportEditorModeInfo.m_id)); + } } const ViewportEditorModesInterface* ViewportEditorModeTracker::GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h index e766bd29b9..d67ea5d725 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h @@ -26,10 +26,10 @@ namespace AzToolsFramework static constexpr AZ::u8 NumEditorModes = 4; //! Sets the specified mode as active. - void SetModeActive(ViewportEditorMode mode); + AZ::Outcome SetModeActive(ViewportEditorMode mode); // Sets the specified mode as inactive. - void SetModeInactive(ViewportEditorMode mode); + AZ::Outcome SetModeInactive(ViewportEditorMode mode); // ViewportEditorModesInterface ... bool IsModeActive(ViewportEditorMode mode) const override; @@ -49,8 +49,8 @@ namespace AzToolsFramework void UnregisterInterface(); // ViewportEditorModeTrackerInterface overrides ... - void RegisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; - void UnregisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + AZ::Outcome RegisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + AZ::Outcome UnregisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; size_t GetTrackedViewportCount() const override; bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index ac61a20bf6..6103482f05 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -19,11 +19,23 @@ namespace UnitTest using ViewportId = ViewportEditorModeInfo::IdType; using ViewportEditorModesInterface = AzToolsFramework::ViewportEditorModesInterface; + void SetModeActiveAndExpectSuccess(ViewportEditorModes& editorModeState, ViewportEditorMode mode) + { + const auto result = editorModeState.SetModeActive(mode); + EXPECT_TRUE(result.IsSuccess()); + } + + void SetModeInactiveAndExpectSuccess(ViewportEditorModes& editorModeState, ViewportEditorMode mode) + { + const auto result = editorModeState.SetModeInactive(mode); + EXPECT_TRUE(result.IsSuccess()); + } + void SetAllModesActive(ViewportEditorModes& editorModeState) { for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { - editorModeState.SetModeActive(static_cast(mode)); + SetModeActiveAndExpectSuccess(editorModeState, static_cast(mode)); } } @@ -31,7 +43,7 @@ namespace UnitTest { for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { - editorModeState.SetModeInactive(static_cast(mode)); + SetModeInactiveAndExpectSuccess(editorModeState, static_cast(mode)); } } @@ -155,7 +167,7 @@ namespace UnitTest TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeActiveActivatesOnlyThatMode) { - m_editorModes.SetModeActive(m_selectedEditorMode); + SetModeActiveAndExpectSuccess(m_editorModes, m_selectedEditorMode); for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { @@ -174,7 +186,7 @@ namespace UnitTest TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeInactiveInactivatesOnlyThatMode) { SetAllModesActive(m_editorModes); - m_editorModes.SetModeInactive(m_selectedEditorMode); + SetModeInactiveAndExpectSuccess(m_editorModes, m_selectedEditorMode); for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { @@ -196,7 +208,9 @@ namespace UnitTest { // Given only the selected mode active SetAllModesInactive(m_editorModes); - m_editorModes.SetModeActive(m_selectedEditorMode); + { + SetModeActiveAndExpectSuccess(m_editorModes, m_selectedEditorMode); + } const auto editorMode = static_cast(mode); if (editorMode == m_selectedEditorMode) @@ -205,7 +219,7 @@ namespace UnitTest } // When other modes are activated - m_editorModes.SetModeActive(editorMode); + SetModeActiveAndExpectSuccess(m_editorModes, editorMode); for (auto expectedMode = 0; expectedMode < ViewportEditorModes::NumEditorModes; expectedMode++) { @@ -230,7 +244,7 @@ namespace UnitTest { // Given only the selected mode inactive SetAllModesActive(m_editorModes); - m_editorModes.SetModeInactive(m_selectedEditorMode); + SetModeInactiveAndExpectSuccess(m_editorModes, m_selectedEditorMode); const auto editorMode = static_cast(mode); if (editorMode == m_selectedEditorMode) @@ -239,7 +253,7 @@ namespace UnitTest } // When other modes are deactivated - m_editorModes.SetModeInactive(editorMode); + SetModeInactiveAndExpectSuccess(m_editorModes, editorMode); for (auto expectedMode = 0; expectedMode < ViewportEditorModes::NumEditorModes; expectedMode++) { @@ -267,18 +281,16 @@ namespace UnitTest AzToolsFramework::ViewportEditorMode::Focus, AzToolsFramework::ViewportEditorMode::Pick)); - TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeActiveIssuesErrorMsg) + TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeActiveReturnsError) { - UnitTest::TestRunner::Instance().StartAssertTests(); - m_editorModes.SetModeActive(static_cast(ViewportEditorModes::NumEditorModes)); - EXPECT_EQ(1, UnitTest::TestRunner::Instance().StopAssertTests()); + const auto result = m_editorModes.SetModeActive(static_cast(ViewportEditorModes::NumEditorModes)); + EXPECT_FALSE(result.IsSuccess()); } - TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeInactiveIssuesErrorMsg) + TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeInactiveReturnsError) { - UnitTest::TestRunner::Instance().StartAssertTests(); - m_editorModes.SetModeInactive(static_cast(ViewportEditorModes::NumEditorModes)); - EXPECT_EQ(1, UnitTest::TestRunner::Instance().StopAssertTests()); + const auto result = m_editorModes.SetModeInactive(static_cast(ViewportEditorModes::NumEditorModes)); + EXPECT_FALSE(result.IsSuccess()); } TEST_F(ViewportEditorModeTrackerTestFixture, InitialCentralStateTrackerHasNoViewportEditorModess) @@ -306,7 +318,7 @@ namespace UnitTest EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } - TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButIssuesErrorMsg) + TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButReturnsError) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -315,12 +327,13 @@ namespace UnitTest // When a mode is deactivated for that viewport const auto editorMode = ViewportEditorMode::Default; - UnitTest::ErrorHandler errorHandler(AZStd::string::format( - "Call to UnregisterMode for mode '%u' on id '%i' without precursor call to RegisterMode", static_cast(editorMode), viewportid).c_str()); - m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); + const auto expectedErrorMsg = AZStd::string::format( + "Call to UnregisterMode for mode '%u' on id '%i' without precursor call to RegisterMode", static_cast(editorMode), viewportid); + const auto result = m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); - // Expect a warning to be issued due to no precursor activation of that mode - EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); + // Expect an error due to no precursor activation of that mode + EXPECT_FALSE(result.IsSuccess()); + EXPECT_EQ(result.GetError(), expectedErrorMsg); // Expect that viewport to now be tracked const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); @@ -338,7 +351,7 @@ namespace UnitTest EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); } - TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModesForExistingIdInThatStateIssuesWarningMsg) + TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModesForExistingIdInThatStateReturnsError) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -346,17 +359,12 @@ namespace UnitTest EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); const auto editorMode = ViewportEditorMode::Default; - const auto expectedWarning = AZStd::string::format( - "Duplicate call to RegisterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); - { - UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); - // When the mode is activated for the viewport - m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); + const auto result = m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); - // Expect no warning to be issued as there is no duplicate activation - EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); + // Expect no error as there is no duplicate activation + EXPECT_TRUE(result.IsSuccess()); // Expect the mode to be active for the viewport const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); @@ -366,11 +374,13 @@ namespace UnitTest } { // When the mode is activated again for the viewport - UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); - m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); + const auto result = m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); - // Expect a warning to be issued for the duplicate activation - EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); + // Expect an error for the duplicate activation + const auto expectedErrorMsg = AZStd::string::format( + "Duplicate call to RegisterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); + EXPECT_FALSE(result.IsSuccess()); + EXPECT_EQ(result.GetError(), expectedErrorMsg); // Expect the mode to still be active for the viewport const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); @@ -380,7 +390,7 @@ namespace UnitTest } } - TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModesForExistingIdNotInThatStateIssuesWarningMsg) + TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModesForExistingIdNotInThatStateReturnssError) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -388,18 +398,13 @@ namespace UnitTest EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); const auto editorMode = ViewportEditorMode::Default; - const auto expectedWarning = - AZStd::string::format("Duplicate call to UnregisterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); - { - UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); - // When the mode is activated and then deactivated for the viewport m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); - m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); + const auto result = m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); - // Expect no warning to be issued as there is no duplicate deactivation - EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 0); + // Expect no error as there is no duplicate deactivation + EXPECT_TRUE(result.IsSuccess()); // Expect the mode to be inctive for the viewport const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); @@ -408,13 +413,14 @@ namespace UnitTest EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode)); } { - UnitTest::ErrorHandler errorHandler(expectedWarning.c_str()); - // When the mode is deactivated again for the viewport - m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); + const auto result = m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); - // Expect a warning to be issued for the duplicate deactivation - EXPECT_EQ(errorHandler.GetExpectedWarningCount(), 1); + // Expect an error for the duplicate deactivation + const auto expectedErrorMsg = AZStd::string::format( + "Duplicate call to UnregisterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); + EXPECT_FALSE(result.IsSuccess()); + EXPECT_EQ(result.GetError(), expectedErrorMsg); // Expect the mode to still be inactive for the viewport const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); From acd7d3c27766d929e46acf09479437f067065483 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 20 Sep 2021 12:43:50 +0100 Subject: [PATCH 15/50] Change all nomenclature to Activate/Deactivate for consistency. Signed-off-by: John --- .../API/ViewportEditorModeTrackerInterface.h | 8 +-- ...ViewportEditorModeTrackerNotificationBus.h | 8 +-- .../ViewportEditorModeTracker.cpp | 22 +++---- .../ViewportEditorModeTracker.h | 9 ++- .../Viewport/ViewportEditorModeTests.cpp | 58 +++++++++---------- 5 files changed, 52 insertions(+), 53 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h index ae4f3424eb..bcc8afbe6a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerInterface.h @@ -22,12 +22,12 @@ namespace AzToolsFramework virtual ~ViewportEditorModeTrackerInterface() = default; - //! Registers the specified editor mode as active for the specified viewport. - virtual AZ::Outcome RegisterMode( + //! Activates the specified editor mode for the specified viewport. + virtual AZ::Outcome ActivateMode( const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; - //! Unregisters the specified editor mode as active for the specified viewport. - virtual AZ::Outcome UnregisterMode( + //! Deactivates the specified editor mode for the specified viewport. + virtual AZ::Outcome DeactivateMode( const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0; //! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h index caa762241c..d4e5dd4fbb 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h @@ -52,13 +52,13 @@ namespace AzToolsFramework using BusIdType = ViewportEditorModeInfo::IdType; ////////////////////////////////////////////////////////////////////////// - //! Notifies subscribers of the a given viewport to the entering of the specified editor mode. - virtual void OnEditorModeEnter([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + //! Notifies subscribers of the a given viewport to the activation of the specified editor mode. + virtual void OnEditorModeActivate([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) { } - //! Notifies subscribers of the a given viewport to the exiting of the specified editor mode. - virtual void OnEditorModeExit([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + //! Notifies subscribers of the a given viewport to the deactivation of the specified editor mode. + virtual void OnEditorModeDeactivate([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) { } }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 36c1b09be7..26f724b0aa 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -13,7 +13,7 @@ namespace AzToolsFramework { static constexpr const char* ViewportEditorModeLogWindow = "ViewportEditorMode"; - AZ::Outcome ViewportEditorModes::SetModeActive(ViewportEditorMode mode) + AZ::Outcome ViewportEditorModes::ActivateMode(ViewportEditorMode mode) { if (const AZ::u32 modeIndex = static_cast(mode); modeIndex < NumEditorModes) @@ -28,7 +28,7 @@ namespace AzToolsFramework } } - AZ::Outcome ViewportEditorModes::SetModeInactive(ViewportEditorMode mode) + AZ::Outcome ViewportEditorModes::DeactivateMode(ViewportEditorMode mode) { if (const AZ::u32 modeIndex = static_cast(mode); modeIndex < NumEditorModes) { @@ -63,29 +63,29 @@ namespace AzToolsFramework } } - AZ::Outcome ViewportEditorModeTracker::RegisterMode( + AZ::Outcome ViewportEditorModeTracker::ActivateMode( const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { auto& editorModes = m_viewportEditorModesMap[viewportEditorModeInfo.m_id]; if (editorModes.IsModeActive(mode)) { return AZ::Failure(AZStd::string::format( - "Duplicate call to RegisterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id)); + "Duplicate call to ActivateMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id)); } - if (const auto result = editorModes.SetModeActive(mode); + if (const auto result = editorModes.ActivateMode(mode); !result.IsSuccess()) { return result; } ViewportEditorModeNotificationsBus::Event( - viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeEnter, editorModes, mode); + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeActivate, editorModes, mode); return AZ::Success(); } - AZ::Outcome ViewportEditorModeTracker::UnregisterMode( + AZ::Outcome ViewportEditorModeTracker::DeactivateMode( const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { ViewportEditorModes* editorModes = nullptr; @@ -96,7 +96,7 @@ namespace AzToolsFramework if (!editorModes->IsModeActive(mode)) { return AZ::Failure(AZStd::string::format( - "Duplicate call to UnregisterMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id)); + "Duplicate call to DeactivateMode for mode '%u' on id '%i'", static_cast(mode), viewportEditorModeInfo.m_id)); } } else @@ -105,14 +105,14 @@ namespace AzToolsFramework editorModes = &m_viewportEditorModesMap[viewportEditorModeInfo.m_id]; } - if(const auto result = editorModes->SetModeInactive(mode); + if(const auto result = editorModes->DeactivateMode(mode); !result.IsSuccess()) { return result; } ViewportEditorModeNotificationsBus::Event( - viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeExit, *editorModes, mode); + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeDeactivate, *editorModes, mode); if (modeWasActive) { @@ -121,7 +121,7 @@ namespace AzToolsFramework else { return AZ::Failure(AZStd::string::format( - "Call to UnregisterMode for mode '%u' on id '%i' without precursor call to RegisterMode", static_cast(mode), + "Call to DeactivateMode for mode '%u' on id '%i' without precursor call to ActivateMode", static_cast(mode), viewportEditorModeInfo.m_id)); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h index d67ea5d725..6ae68b39b2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h @@ -21,15 +21,14 @@ namespace AzToolsFramework : public ViewportEditorModesInterface { public: - //! The number of currently supported viewport editor modes. static constexpr AZ::u8 NumEditorModes = 4; //! Sets the specified mode as active. - AZ::Outcome SetModeActive(ViewportEditorMode mode); + AZ::Outcome ActivateMode(ViewportEditorMode mode); // Sets the specified mode as inactive. - AZ::Outcome SetModeInactive(ViewportEditorMode mode); + AZ::Outcome DeactivateMode(ViewportEditorMode mode); // ViewportEditorModesInterface ... bool IsModeActive(ViewportEditorMode mode) const override; @@ -49,8 +48,8 @@ namespace AzToolsFramework void UnregisterInterface(); // ViewportEditorModeTrackerInterface overrides ... - AZ::Outcome RegisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; - AZ::Outcome UnregisterMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + AZ::Outcome ActivateMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; + AZ::Outcome DeactivateMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; size_t GetTrackedViewportCount() const override; bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override; diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 6103482f05..b3acd91bfe 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -19,15 +19,15 @@ namespace UnitTest using ViewportId = ViewportEditorModeInfo::IdType; using ViewportEditorModesInterface = AzToolsFramework::ViewportEditorModesInterface; - void SetModeActiveAndExpectSuccess(ViewportEditorModes& editorModeState, ViewportEditorMode mode) + void ActivateModeAndExpectSuccess(ViewportEditorModes& editorModeState, ViewportEditorMode mode) { - const auto result = editorModeState.SetModeActive(mode); + const auto result = editorModeState.ActivateMode(mode); EXPECT_TRUE(result.IsSuccess()); } - void SetModeInactiveAndExpectSuccess(ViewportEditorModes& editorModeState, ViewportEditorMode mode) + void DeactivateModeAndExpectSuccess(ViewportEditorModes& editorModeState, ViewportEditorMode mode) { - const auto result = editorModeState.SetModeInactive(mode); + const auto result = editorModeState.DeactivateMode(mode); EXPECT_TRUE(result.IsSuccess()); } @@ -35,7 +35,7 @@ namespace UnitTest { for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { - SetModeActiveAndExpectSuccess(editorModeState, static_cast(mode)); + ActivateModeAndExpectSuccess(editorModeState, static_cast(mode)); } } @@ -43,7 +43,7 @@ namespace UnitTest { for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { - SetModeInactiveAndExpectSuccess(editorModeState, static_cast(mode)); + DeactivateModeAndExpectSuccess(editorModeState, static_cast(mode)); } } @@ -111,12 +111,12 @@ namespace UnitTest return m_editorModes; } - void OnEditorModeEnter([[maybe_unused]]const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override + void OnEditorModeActivate([[maybe_unused]]const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override { m_editorModes[mode].m_onEnter = true; } - virtual void OnEditorModeExit([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override + virtual void OnEditorModeDeactivate([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override { m_editorModes[mode].m_onExit = true; } @@ -167,7 +167,7 @@ namespace UnitTest TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeActiveActivatesOnlyThatMode) { - SetModeActiveAndExpectSuccess(m_editorModes, m_selectedEditorMode); + ActivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode); for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { @@ -186,7 +186,7 @@ namespace UnitTest TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeInactiveInactivatesOnlyThatMode) { SetAllModesActive(m_editorModes); - SetModeInactiveAndExpectSuccess(m_editorModes, m_selectedEditorMode); + DeactivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode); for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) { @@ -209,7 +209,7 @@ namespace UnitTest // Given only the selected mode active SetAllModesInactive(m_editorModes); { - SetModeActiveAndExpectSuccess(m_editorModes, m_selectedEditorMode); + ActivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode); } const auto editorMode = static_cast(mode); @@ -219,7 +219,7 @@ namespace UnitTest } // When other modes are activated - SetModeActiveAndExpectSuccess(m_editorModes, editorMode); + ActivateModeAndExpectSuccess(m_editorModes, editorMode); for (auto expectedMode = 0; expectedMode < ViewportEditorModes::NumEditorModes; expectedMode++) { @@ -244,7 +244,7 @@ namespace UnitTest { // Given only the selected mode inactive SetAllModesActive(m_editorModes); - SetModeInactiveAndExpectSuccess(m_editorModes, m_selectedEditorMode); + DeactivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode); const auto editorMode = static_cast(mode); if (editorMode == m_selectedEditorMode) @@ -253,7 +253,7 @@ namespace UnitTest } // When other modes are deactivated - SetModeInactiveAndExpectSuccess(m_editorModes, editorMode); + DeactivateModeAndExpectSuccess(m_editorModes, editorMode); for (auto expectedMode = 0; expectedMode < ViewportEditorModes::NumEditorModes; expectedMode++) { @@ -283,13 +283,13 @@ namespace UnitTest TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeActiveReturnsError) { - const auto result = m_editorModes.SetModeActive(static_cast(ViewportEditorModes::NumEditorModes)); + const auto result = m_editorModes.ActivateMode(static_cast(ViewportEditorModes::NumEditorModes)); EXPECT_FALSE(result.IsSuccess()); } TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeInactiveReturnsError) { - const auto result = m_editorModes.SetModeInactive(static_cast(ViewportEditorModes::NumEditorModes)); + const auto result = m_editorModes.DeactivateMode(static_cast(ViewportEditorModes::NumEditorModes)); EXPECT_FALSE(result.IsSuccess()); } @@ -307,7 +307,7 @@ namespace UnitTest // When a mode is activated for that viewport const auto editorMode = ViewportEditorMode::Default; - m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.ActivateMode({ viewportid }, editorMode); const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }); // Expect that viewport to now be tracked @@ -328,8 +328,8 @@ namespace UnitTest // When a mode is deactivated for that viewport const auto editorMode = ViewportEditorMode::Default; const auto expectedErrorMsg = AZStd::string::format( - "Call to UnregisterMode for mode '%u' on id '%i' without precursor call to RegisterMode", static_cast(editorMode), viewportid); - const auto result = m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); + "Call to DeactivateMode for mode '%u' on id '%i' without precursor call to ActivateMode", static_cast(editorMode), viewportid); + const auto result = m_viewportEditorModeTracker.DeactivateMode({ viewportid }, editorMode); // Expect an error due to no precursor activation of that mode EXPECT_FALSE(result.IsSuccess()); @@ -361,7 +361,7 @@ namespace UnitTest const auto editorMode = ViewportEditorMode::Default; { // When the mode is activated for the viewport - const auto result = m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); + const auto result = m_viewportEditorModeTracker.ActivateMode({ viewportid }, editorMode); // Expect no error as there is no duplicate activation EXPECT_TRUE(result.IsSuccess()); @@ -374,11 +374,11 @@ namespace UnitTest } { // When the mode is activated again for the viewport - const auto result = m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); + const auto result = m_viewportEditorModeTracker.ActivateMode({ viewportid }, editorMode); // Expect an error for the duplicate activation const auto expectedErrorMsg = AZStd::string::format( - "Duplicate call to RegisterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); + "Duplicate call to ActivateMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); EXPECT_FALSE(result.IsSuccess()); EXPECT_EQ(result.GetError(), expectedErrorMsg); @@ -400,8 +400,8 @@ namespace UnitTest const auto editorMode = ViewportEditorMode::Default; { // When the mode is activated and then deactivated for the viewport - m_viewportEditorModeTracker.RegisterMode({ viewportid }, editorMode); - const auto result = m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); + m_viewportEditorModeTracker.ActivateMode({ viewportid }, editorMode); + const auto result = m_viewportEditorModeTracker.DeactivateMode({ viewportid }, editorMode); // Expect no error as there is no duplicate deactivation EXPECT_TRUE(result.IsSuccess()); @@ -414,11 +414,11 @@ namespace UnitTest } { // When the mode is deactivated again for the viewport - const auto result = m_viewportEditorModeTracker.UnregisterMode({ viewportid }, editorMode); + const auto result = m_viewportEditorModeTracker.DeactivateMode({ viewportid }, editorMode); // Expect an error for the duplicate deactivation const auto expectedErrorMsg = AZStd::string::format( - "Duplicate call to UnregisterMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); + "Duplicate call to DeactivateMode for mode '%u' on id '%i'", static_cast(editorMode), viewportid); EXPECT_FALSE(result.IsSuccess()); EXPECT_EQ(result.GetError(), expectedErrorMsg); @@ -446,7 +446,7 @@ namespace UnitTest { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); - m_viewportEditorModeTracker.RegisterMode({ mode }, editorMode); + m_viewportEditorModeTracker.ActivateMode({ mode }, editorMode); } for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -478,8 +478,8 @@ namespace UnitTest { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); - m_viewportEditorModeTracker.RegisterMode({ mode }, editorMode); - m_viewportEditorModeTracker.UnregisterMode({ mode }, editorMode); + m_viewportEditorModeTracker.ActivateMode({ mode }, editorMode); + m_viewportEditorModeTracker.DeactivateMode({ mode }, editorMode); } for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) From 5a25511432fe3c9ad4272034c378356d6d3a651e Mon Sep 17 00:00:00 2001 From: John Date: Mon, 20 Sep 2021 13:06:01 +0100 Subject: [PATCH 16/50] Change tense of notification bus methods. Signed-off-by: John --- .../API/ViewportEditorModeTrackerNotificationBus.h | 4 ++-- .../ViewportSelection/ViewportEditorModeTracker.cpp | 4 ++-- .../Tests/Viewport/ViewportEditorModeTests.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h index d4e5dd4fbb..42a1cb0113 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h @@ -53,12 +53,12 @@ namespace AzToolsFramework ////////////////////////////////////////////////////////////////////////// //! Notifies subscribers of the a given viewport to the activation of the specified editor mode. - virtual void OnEditorModeActivate([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + virtual void OnEditorModeActivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) { } //! Notifies subscribers of the a given viewport to the deactivation of the specified editor mode. - virtual void OnEditorModeDeactivate([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + virtual void OnEditorModeDeactivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) { } }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 26f724b0aa..05d21fbf41 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -80,7 +80,7 @@ namespace AzToolsFramework } ViewportEditorModeNotificationsBus::Event( - viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeActivate, editorModes, mode); + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeActivated, editorModes, mode); return AZ::Success(); } @@ -112,7 +112,7 @@ namespace AzToolsFramework } ViewportEditorModeNotificationsBus::Event( - viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeDeactivate, *editorModes, mode); + viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeDeactivated, *editorModes, mode); if (modeWasActive) { diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index b3acd91bfe..527f77b9b0 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -111,12 +111,12 @@ namespace UnitTest return m_editorModes; } - void OnEditorModeActivate([[maybe_unused]]const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override + void OnEditorModeActivated([[maybe_unused]]const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override { m_editorModes[mode].m_onEnter = true; } - virtual void OnEditorModeDeactivate([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override + virtual void OnEditorModeDeactivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override { m_editorModes[mode].m_onExit = true; } From 1dc38518afb4d60f6a472aaa93515be1baef310b Mon Sep 17 00:00:00 2001 From: John Date: Mon, 20 Sep 2021 14:48:39 +0100 Subject: [PATCH 17/50] Fix malformed string format. Signed-off-by: John --- .../ViewportSelection/ViewportEditorModeTracker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 05d21fbf41..fc16bf3384 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -24,7 +24,7 @@ namespace AzToolsFramework else { return AZ::Failure( - AZStd::string::format(ViewportEditorModeLogWindow, false, "Cannot activate mode %u, mode is not recognized", modeIndex)); + AZStd::string::format(ViewportEditorModeLogWindow, "Cannot activate mode %u, mode is not recognized", modeIndex)); } } @@ -38,7 +38,7 @@ namespace AzToolsFramework else { return AZ::Failure( - AZStd::string::format(ViewportEditorModeLogWindow, false, "Cannot deactivate mode %u, mode is not recognized", modeIndex)); + AZStd::string::format(ViewportEditorModeLogWindow, "Cannot deactivate mode %u, mode is not recognized", modeIndex)); } } From 7f3872f41b3c0f903dfe270419c88a0c6e5ac7cb Mon Sep 17 00:00:00 2001 From: John Date: Mon, 20 Sep 2021 15:27:34 +0100 Subject: [PATCH 18/50] Fix malformed string format (again). Signed-off-by: John --- .../ViewportSelection/ViewportEditorModeTracker.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index fc16bf3384..4adddb02e1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -11,8 +11,6 @@ namespace AzToolsFramework { - static constexpr const char* ViewportEditorModeLogWindow = "ViewportEditorMode"; - AZ::Outcome ViewportEditorModes::ActivateMode(ViewportEditorMode mode) { if (const AZ::u32 modeIndex = static_cast(mode); @@ -24,7 +22,7 @@ namespace AzToolsFramework else { return AZ::Failure( - AZStd::string::format(ViewportEditorModeLogWindow, "Cannot activate mode %u, mode is not recognized", modeIndex)); + AZStd::string::format("Cannot activate mode %u, mode is not recognized", modeIndex)); } } @@ -38,7 +36,7 @@ namespace AzToolsFramework else { return AZ::Failure( - AZStd::string::format(ViewportEditorModeLogWindow, "Cannot deactivate mode %u, mode is not recognized", modeIndex)); + AZStd::string::format("Cannot deactivate mode %u, mode is not recognized", modeIndex)); } } From 5a36a375a6f0ab0183662dff0769483f401ccea8 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 20 Sep 2021 15:44:18 +0100 Subject: [PATCH 19/50] Fix Linux warning. Signed-off-by: John --- .../Tests/Viewport/ViewportEditorModeTests.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 527f77b9b0..3954ef6dc6 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -446,7 +446,7 @@ namespace UnitTest { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); - m_viewportEditorModeTracker.ActivateMode({ mode }, editorMode); + m_viewportEditorModeTracker.ActivateMode({ viewportId }, editorMode); } for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -478,8 +478,8 @@ namespace UnitTest { const ViewportId viewportId = mode; const ViewportEditorMode editorMode = static_cast(mode); - m_viewportEditorModeTracker.ActivateMode({ mode }, editorMode); - m_viewportEditorModeTracker.DeactivateMode({ mode }, editorMode); + m_viewportEditorModeTracker.ActivateMode({ viewportId }, editorMode); + m_viewportEditorModeTracker.DeactivateMode({ viewportId }, editorMode); } for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) From beaa90a96886baace124f79267354d8e60e14c37 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 22 Sep 2021 16:24:33 +0100 Subject: [PATCH 20/50] Call sites for editor mode activate/deactivate. Signed-off-by: John --- AutomatedTesting/Levels/Floof/Floof.ly | 3 ++ AutomatedTesting/Levels/Floof/filelist.xml | 6 ++++ AutomatedTesting/Levels/Floof/level.pak | 3 ++ AutomatedTesting/Levels/Floof/tags.txt | 12 +++++++ .../ComponentMode/ComponentModeCollection.cpp | 4 +-- .../PropertyEditor/PropertyEntityIdCtrl.cpp | 5 +-- .../UnitTest/AzToolsFrameworkTestHelpers.h | 4 ++- .../EditorDefaultSelection.cpp | 32 +++++++++++++++++++ .../EditorDefaultSelection.h | 5 +++ .../EditorInteractionSystemComponent.cpp | 28 +++++++++++++--- .../EditorInteractionSystemComponent.h | 15 +++++++++ ...ractionSystemViewportSelectionRequestBus.h | 5 +-- .../EditorPickEntitySelection.cpp | 17 ++++++++++ .../EditorPickEntitySelection.h | 7 +++- .../ViewportEditorModeTracker.cpp | 16 ---------- .../ViewportEditorModeTracker.h | 6 ---- ...EditorTransformComponentSelectionTests.cpp | 3 +- .../Viewport/ViewportEditorModeTests.cpp | 22 +++++++++---- 18 files changed, 152 insertions(+), 41 deletions(-) create mode 100644 AutomatedTesting/Levels/Floof/Floof.ly create mode 100644 AutomatedTesting/Levels/Floof/filelist.xml create mode 100644 AutomatedTesting/Levels/Floof/level.pak create mode 100644 AutomatedTesting/Levels/Floof/tags.txt diff --git a/AutomatedTesting/Levels/Floof/Floof.ly b/AutomatedTesting/Levels/Floof/Floof.ly new file mode 100644 index 0000000000..aa7ed0d9db --- /dev/null +++ b/AutomatedTesting/Levels/Floof/Floof.ly @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3473284ee7f390280fb71090da8c1754791a3753fc1532e6b6a69842f2d4e23f +size 8605 diff --git a/AutomatedTesting/Levels/Floof/filelist.xml b/AutomatedTesting/Levels/Floof/filelist.xml new file mode 100644 index 0000000000..82409c84cd --- /dev/null +++ b/AutomatedTesting/Levels/Floof/filelist.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/AutomatedTesting/Levels/Floof/level.pak b/AutomatedTesting/Levels/Floof/level.pak new file mode 100644 index 0000000000..e9374fe73f --- /dev/null +++ b/AutomatedTesting/Levels/Floof/level.pak @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9577257254e5938790ec3445689a9b59bc1715c7f1aaaad81150b9468e72cbfa +size 1346 diff --git a/AutomatedTesting/Levels/Floof/tags.txt b/AutomatedTesting/Levels/Floof/tags.txt new file mode 100644 index 0000000000..0d6c1880e7 --- /dev/null +++ b/AutomatedTesting/Levels/Floof/tags.txt @@ -0,0 +1,12 @@ +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp index 0259142135..5527a35f88 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp @@ -8,8 +8,8 @@ #include "ComponentModeCollection.h" -#include #include +#include namespace AzToolsFramework { @@ -17,7 +17,7 @@ namespace AzToolsFramework { AZ_CLASS_ALLOCATOR_IMPL(ComponentModeCollection, AZ::SystemAllocator, 0) - static const char* const s_nextActiveComponentModeTitle = "Edit Next"; + static const char* const s_nextActiveComponentModeTitle = "Edit Next"; static const char* const s_previousActiveComponentModeTitle = "Edit Previous"; static const char* const s_nextActiveComponentModeDesc = "Move to the next component"; static const char* const s_prevActiveComponentModeDesc = "Move to the previous component"; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.cpp index f98638fd69..7a9a5a4d7a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.cpp @@ -119,11 +119,12 @@ namespace AzToolsFramework // replace the default input handler with one specific for dealing with // entity selection in the viewport + EditorInteractionSystemViewportSelectionRequestBus::Event( GetEntityContextId(), &EditorInteractionSystemViewportSelection::SetHandler, - [](const EditorVisibleEntityDataCache* entityDataCache) + [](const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) { - return AZStd::make_unique(entityDataCache); + return AZStd::make_unique(entityDataCache, viewportEditorModeTracker); }); if (!pickModeEntityContextId.IsNull()) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h index b3a660d0f2..a67562af76 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -166,7 +167,8 @@ namespace UnitTest m_editorActions.Connect(); const auto viewportHandlerBuilder = - [this](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache) + [this](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache, + [[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker) { // create the default viewport (handles ComponentMode) AZStd::unique_ptr defaultSelection = diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp index 7903668409..0b23756365 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp @@ -9,6 +9,7 @@ #include "EditorDefaultSelection.h" #include +#include #include #include #include @@ -30,10 +31,25 @@ namespace AzToolsFramework m_transformComponentSelection = AZStd::make_unique(entityDataCache); } + EditorDefaultSelection::EditorDefaultSelection( + const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) + : EditorDefaultSelection(entityDataCache) + { + m_viewportEditorModeTracker = viewportEditorModeTracker; + if (m_viewportEditorModeTracker) + { + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default); + } + } + EditorDefaultSelection::~EditorDefaultSelection() { ComponentModeFramework::ComponentModeSystemRequestBus::Handler::BusDisconnect(); ActionOverrideRequestBus::Handler::BusDisconnect(); + if (m_viewportEditorModeTracker) + { + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default); + } } void EditorDefaultSelection::SetOverridePhantomWidget(QWidget* phantomOverrideWidget) @@ -91,6 +107,14 @@ namespace AzToolsFramework m_componentModeCollection.BeginComponentMode(); + // this call to activate the component mode editor state should eventually replace the bus call in + // ComponentModeCollection::BeginComponentMode() to EditorComponentModeNotifications::EnteredComponentMode + // such that all of the notifications for activating/deactivating the different editor modes are in a central location + if (m_viewportEditorModeTracker) + { + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); + } + // refresh button ui ToolsApplicationEvents::Bus::Broadcast( &ToolsApplicationEvents::Bus::Events::InvalidatePropertyDisplay, PropertyModificationRefreshLevel::Refresh_EntireTree); @@ -100,6 +124,14 @@ namespace AzToolsFramework { m_componentModeCollection.EndComponentMode(); + // this call to deactivate the component mode editor state should eventually replace the bus call in + // ComponentModeCollection::EndComponentMode() to EditorComponentModeNotifications::LeftComponentMode + // such that all of the notifications for activating/deactivating the different editor modes are in a central location + if (m_viewportEditorModeTracker) + { + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); + } + if (m_transformComponentSelection) { // safe to show manipulators again diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h index 5763bf227c..6a53a2b186 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h @@ -15,6 +15,8 @@ namespace AzToolsFramework { + class ViewportEditorModeTrackerInterface; + //! The default selection/input handler for the editor (includes handling ComponentMode). class EditorDefaultSelection : public ViewportInteraction::InternalViewportSelectionRequests @@ -26,6 +28,7 @@ namespace AzToolsFramework //! @cond explicit EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache); + explicit EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker); EditorDefaultSelection(const EditorDefaultSelection&) = delete; EditorDefaultSelection& operator=(const EditorDefaultSelection&) = delete; virtual ~EditorDefaultSelection(); @@ -110,5 +113,7 @@ namespace AzToolsFramework AZStd::shared_ptr m_manipulatorManager; //!< The default manipulator manager. ViewportInteraction::MouseInteraction m_currentInteraction; //!< Current mouse interaction to be used for drawing manipulators. + ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; //!< Tracker for activating/deactivating viewport editor modes. + }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp index 7002436d13..7f84038ace 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp @@ -10,9 +10,28 @@ #include #include +#include namespace AzToolsFramework { + EditorInteractionSystemComponent::EditorInteractionSystemComponent() + : m_viewportEditorMode(AZStd::make_unique()) + { + if (AZ::Interface::Get() == nullptr) + { + AZ::Interface::Register(m_viewportEditorMode.get()); + } + } + + EditorInteractionSystemComponent::~EditorInteractionSystemComponent() + { + m_interactionRequests.reset(); + if (AZ::Interface::Get() != nullptr) + { + AZ::Interface::Unregister(m_viewportEditorMode.get()); + } + } + void EditorInteractionSystemComponent::Activate() { EditorInteractionSystemViewportSelectionRequestBus::Handler::BusConnect(GetEntityContextId()); @@ -41,7 +60,8 @@ namespace AzToolsFramework return m_interactionRequests->InternalHandleMouseManipulatorInteraction(mouseInteraction); } - void EditorInteractionSystemComponent::SetHandler(const ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder) + void EditorInteractionSystemComponent::SetHandler( + const ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder) { // when setting a handler, make sure we're connected to the ViewportDebugDisplayEventBus so we // can forward calls to the specific type implementing ViewportSelectionRequests @@ -59,7 +79,7 @@ namespace AzToolsFramework m_entityDataCache = AZStd::make_unique(); m_interactionRequests.reset(); // BusConnect/Disconnect in constructor/destructor, // so have to reset before assigning the new one - m_interactionRequests = interactionRequestsBuilder(m_entityDataCache.get()); + m_interactionRequests = interactionRequestsBuilder(m_entityDataCache.get(), m_viewportEditorMode.get()); } EditorInteractionSystemViewportSelectionRequestBus::Handler::BusConnect(GetEntityContextId()); @@ -68,9 +88,9 @@ namespace AzToolsFramework void EditorInteractionSystemComponent::SetDefaultHandler() { SetHandler( - [](const EditorVisibleEntityDataCache* entityDataCache) + [](const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) { - return AZStd::make_unique(entityDataCache); + return AZStd::make_unique(entityDataCache, viewportEditorModeTracker); }); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h index 17521eab14..7bbc0ee009 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h @@ -12,8 +12,18 @@ #include #include + + + + + + +#include + namespace AzToolsFramework { + //class ViewportEditorModeTracker; + //! System Component to wrap active input handler. //! EditorInteractionSystemComponent is notified of viewport mouse events from RenderViewport //! and forwards them to a concrete implementation of ViewportSelectionRequests. @@ -26,6 +36,9 @@ namespace AzToolsFramework public: AZ_COMPONENT(EditorInteractionSystemComponent, "{146D0317-AF42-45AB-A953-F54198525DD5}") + EditorInteractionSystemComponent(); + ~EditorInteractionSystemComponent(); + static void Reflect(AZ::ReflectContext* context); // EditorInteractionSystemViewportSelectionRequestBus @@ -54,5 +67,7 @@ namespace AzToolsFramework AZStd::unique_ptr m_interactionRequests; //!< Hold a concrete implementation of //!< ViewportSelectionRequests to handle viewport //!< input and drawing for the Editor. + + AZStd::unique_ptr m_viewportEditorMode; //!< Editor mode tracker for each viewport. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h index ee3f83f74d..3579460ca0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h @@ -17,6 +17,7 @@ namespace AzToolsFramework { class EditorVisibleEntityDataCache; + class ViewportEditorModeTrackerInterface; //! Bus to handle all mouse events originating from the viewport. //! Coordinated by the EditorInteractionSystemComponent @@ -32,8 +33,8 @@ namespace AzToolsFramework }; //! Alias for factory function to create a new type implementing the ViewportSelectionRequests interface. - using ViewportSelectionRequestsBuilderFn = - AZStd::function(const EditorVisibleEntityDataCache*)>; + using ViewportSelectionRequestsBuilderFn = AZStd::function( + const EditorVisibleEntityDataCache*, ViewportEditorModeTrackerInterface*)>; //! Interface for system component implementing the ViewportSelectionRequests interface. //! This interface also includes a setter to set a custom handler also implementing diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp index ea1bc73056..9306deb69d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp @@ -8,6 +8,7 @@ #include "EditorPickEntitySelection.h" +#include #include #include @@ -20,12 +21,28 @@ namespace AzToolsFramework { } + EditorPickEntitySelection::EditorPickEntitySelection( + const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) + : EditorPickEntitySelection(entityDataCache) + { + m_viewportEditorModeTracker = viewportEditorModeTracker; + if (m_viewportEditorModeTracker) + { + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick); + } + } + EditorPickEntitySelection::~EditorPickEntitySelection() { if (m_hoveredEntityId.IsValid()) { ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetEntityHighlighted, m_hoveredEntityId, false); } + + if (m_viewportEditorModeTracker) + { + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick); + } } // note: entityIdUnderCursor is the authoritative entityId we get each frame by querying diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h index e8d83af932..511111743a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h @@ -13,6 +13,8 @@ namespace AzToolsFramework { + class ViewportEditorModeTrackerInterface; + //! Viewport interaction that will handle assigning an entity in the viewport to //! an entity field in the entity inspector. class EditorPickEntitySelection : public ViewportInteraction::InternalViewportSelectionRequests @@ -20,7 +22,9 @@ namespace AzToolsFramework public: AZ_CLASS_ALLOCATOR_DECL - EditorPickEntitySelection(const EditorVisibleEntityDataCache* entityDataCache); + explicit EditorPickEntitySelection(const EditorVisibleEntityDataCache* entityDataCache); + explicit EditorPickEntitySelection( + const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker); ~EditorPickEntitySelection(); private: @@ -32,5 +36,6 @@ namespace AzToolsFramework AZStd::unique_ptr m_editorHelpers; //!< Editor visualization of entities (icons, shapes, debug visuals etc). AZ::EntityId m_hoveredEntityId; //!< What EntityId is the mouse currently hovering over (if any). AZ::EntityId m_cachedEntityIdUnderCursor; //!< Store the EntityId on each mouse move for use in Display. + ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; //!< Tracker for activating/deactivating viewport editor modes. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 4adddb02e1..105712c789 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -45,22 +45,6 @@ namespace AzToolsFramework return m_editorModes[static_cast(mode)]; } - void ViewportEditorModeTracker::RegisterInterface() - { - if (AZ::Interface::Get() == nullptr) - { - AZ::Interface::Register(this); - } - } - - void ViewportEditorModeTracker::UnregisterInterface() - { - if (AZ::Interface::Get() != nullptr) - { - AZ::Interface::Unregister(this); - } - } - AZ::Outcome ViewportEditorModeTracker::ActivateMode( const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h index 6ae68b39b2..5b382c44e7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h @@ -41,12 +41,6 @@ namespace AzToolsFramework : public ViewportEditorModeTrackerInterface { public: - //! Registers this object with the AZ::Interface. - void RegisterInterface(); - - //! Unregisters this object with the AZ::Interface. - void UnregisterInterface(); - // ViewportEditorModeTrackerInterface overrides ... AZ::Outcome ActivateMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; AZ::Outcome DeactivateMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; diff --git a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp index 449c4549be..1316523f29 100644 --- a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp @@ -343,7 +343,8 @@ namespace UnitTest using AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus; EditorInteractionSystemViewportSelectionRequestBus::Event( AzToolsFramework::GetEntityContextId(), &EditorInteractionSystemViewportSelectionRequestBus::Events::SetHandler, - [](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache) + [](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache, + [[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker) { return AZStd::make_unique(entityDataCache); }); diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 3954ef6dc6..b2b75e22a7 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -152,6 +152,12 @@ namespace UnitTest AZStd::array, ViewportEditorModes::NumEditorModes> m_editorModeHandlers; }; + // Fixture for testing the integration of viewport editor mode state tracker + class ViewportEditorModeTrackerIntegrationTestFixture + : public ToolsApplicationFixture + { + }; + TEST_F(ViewportEditorModesTestsFixture, NumberOfEditorModesIsEqualTo4) { EXPECT_EQ(ViewportEditorModes::NumEditorModes, 4); @@ -298,7 +304,7 @@ namespace UnitTest EXPECT_EQ(m_viewportEditorModeTracker.GetTrackedViewportCount(), 0); } - TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) + TEST_F(ViewportEditorModeTrackerTestFixture, ActivatingViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -318,7 +324,7 @@ namespace UnitTest EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } - TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButReturnsError) + TEST_F(ViewportEditorModeTrackerTestFixture, DeactivatingViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButReturnsError) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -351,7 +357,7 @@ namespace UnitTest EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); } - TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModesForExistingIdInThatStateReturnsError) + TEST_F(ViewportEditorModeTrackerTestFixture, ActivatingViewportEditorModesForExistingIdInThatStateReturnsError) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -390,7 +396,7 @@ namespace UnitTest } } - TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModesForExistingIdNotInThatStateReturnssError) + TEST_F(ViewportEditorModeTrackerTestFixture, DeactivatingViewportEditorModesForExistingIdNotInThatStateReturnssError) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -432,7 +438,7 @@ namespace UnitTest TEST_F( ViewportEditorModePublisherTestFixture, - RegisteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeRegisterEventForAllSubscribers) + ActivatingViewportEditorModesForExistingIdPublishesOnViewportEditorModeActivateEventForAllSubscribers) { // Given a set of subscribers tracking the editor modes for their exclusive viewport for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -465,7 +471,7 @@ namespace UnitTest TEST_F( ViewportEditorModePublisherTestFixture, - UnregisteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeUnregisterEventForAllSubscribers) + DeactivatingViewportEditorModesForExistingIdPublishesOnViewportEditorModeDeactivatingEventForAllSubscribers) { // Given a set of subscribers tracking the editor modes for their exclusive viewport for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -495,4 +501,8 @@ namespace UnitTest EXPECT_TRUE(expectedEditorModeSet->second.m_onExit); } } + + TEST_F(ViewportEditorModeTrackerIntegrationTestFixture, FOO) + { + } } // namespace UnitTest From 4909c91614389d48db63e4216a3f4a4ed2ae8389 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 22 Sep 2021 16:46:44 +0100 Subject: [PATCH 21/50] Move Component editor mode logic to ComponentModeCollection. Signed-off-by: John --- .../ComponentMode/ComponentModeCollection.cpp | 21 +++++++++++++++++++ .../ComponentMode/ComponentModeCollection.h | 3 +++ .../EditorDefaultSelection.cpp | 16 -------------- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp index 5527a35f88..dddaa679bf 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp @@ -9,6 +9,7 @@ #include "ComponentModeCollection.h" #include +#include #include namespace AzToolsFramework @@ -119,6 +120,11 @@ namespace AzToolsFramework } }; + ComponentModeCollection::ComponentModeCollection(ViewportEditorModeTrackerInterface* viewportEditorModeTracker) + : m_viewportEditorModeTracker(viewportEditorModeTracker) + { + } + void ComponentModeCollection::AddComponentMode( const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid componentType, const ComponentModeFactoryFunction& componentModeBuilder) @@ -209,6 +215,14 @@ namespace AzToolsFramework GetEntityContextId(), &EditorComponentModeNotifications::EnteredComponentMode, m_activeComponentTypes); + // this call to activate the component mode editor state should eventually replace the bus call in + // ComponentModeCollection::BeginComponentMode() to EditorComponentModeNotifications::EnteredComponentMode + // such that all of the notifications for activating/deactivating the different editor modes are in a central location + if (m_viewportEditorModeTracker) + { + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); + } + // enable actions for the first/primary ComponentMode // note: if multiple ComponentModes are activated at the same time, actions // are not available together, the 'active' mode will bind its actions one at a time @@ -282,6 +296,13 @@ namespace AzToolsFramework &EditorComponentModeNotifications::LeftComponentMode, m_activeComponentTypes); + // this call to deactivate the component mode editor state should eventually replace the bus call in + // ComponentModeCollection::EndComponentMode() to EditorComponentModeNotifications::LeftComponentMode + // such that all of the notifications for activating/deactivating the different editor modes are in a central location + if (m_viewportEditorModeTracker) + { + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); + } // clear stored modes and builders for this ComponentMode // TLDR: avoid 'use after free' error diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h index 7dd97dc0c9..b295d6103b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h @@ -15,6 +15,7 @@ namespace AzToolsFramework { class EditorMetricsEventsBusTraits; + class ViewportEditorModeTrackerInterface; namespace ComponentModeFramework { @@ -26,6 +27,7 @@ namespace AzToolsFramework /// @cond ComponentModeCollection() = default; + ComponentModeCollection(ViewportEditorModeTrackerInterface* viewportEditorModeTracker); ~ComponentModeCollection() = default; ComponentModeCollection(const ComponentModeCollection&) = delete; ComponentModeCollection& operator=(const ComponentModeCollection&) = delete; @@ -101,6 +103,7 @@ namespace AzToolsFramework size_t m_selectedComponentModeIndex = 0; ///< Index into the array of active ComponentModes, current index is 'selected' ComponentMode. bool m_adding = false; ///< Are we currently adding individual ComponentModes to the Editor wide ComponentMode. bool m_componentMode = false; ///< Editor (global) ComponentMode flag - is ComponentMode active or not. + ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; //!< Tracker for activating/deactivating viewport editor modes. }; } // namespace ComponentModeFramework } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp index 0b23756365..321549585a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp @@ -107,14 +107,6 @@ namespace AzToolsFramework m_componentModeCollection.BeginComponentMode(); - // this call to activate the component mode editor state should eventually replace the bus call in - // ComponentModeCollection::BeginComponentMode() to EditorComponentModeNotifications::EnteredComponentMode - // such that all of the notifications for activating/deactivating the different editor modes are in a central location - if (m_viewportEditorModeTracker) - { - m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); - } - // refresh button ui ToolsApplicationEvents::Bus::Broadcast( &ToolsApplicationEvents::Bus::Events::InvalidatePropertyDisplay, PropertyModificationRefreshLevel::Refresh_EntireTree); @@ -124,14 +116,6 @@ namespace AzToolsFramework { m_componentModeCollection.EndComponentMode(); - // this call to deactivate the component mode editor state should eventually replace the bus call in - // ComponentModeCollection::EndComponentMode() to EditorComponentModeNotifications::LeftComponentMode - // such that all of the notifications for activating/deactivating the different editor modes are in a central location - if (m_viewportEditorModeTracker) - { - m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); - } - if (m_transformComponentSelection) { // safe to show manipulators again From 071d3eaa311046d2850a7957b74e5d475c220a54 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 22 Sep 2021 16:49:22 +0100 Subject: [PATCH 22/50] Delete non-source data. Signed-off-by: John --- AutomatedTesting/Levels/Floof/Floof.ly | 3 --- AutomatedTesting/Levels/Floof/filelist.xml | 6 ------ AutomatedTesting/Levels/Floof/level.pak | 3 --- AutomatedTesting/Levels/Floof/tags.txt | 12 ------------ 4 files changed, 24 deletions(-) delete mode 100644 AutomatedTesting/Levels/Floof/Floof.ly delete mode 100644 AutomatedTesting/Levels/Floof/filelist.xml delete mode 100644 AutomatedTesting/Levels/Floof/level.pak delete mode 100644 AutomatedTesting/Levels/Floof/tags.txt diff --git a/AutomatedTesting/Levels/Floof/Floof.ly b/AutomatedTesting/Levels/Floof/Floof.ly deleted file mode 100644 index aa7ed0d9db..0000000000 --- a/AutomatedTesting/Levels/Floof/Floof.ly +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3473284ee7f390280fb71090da8c1754791a3753fc1532e6b6a69842f2d4e23f -size 8605 diff --git a/AutomatedTesting/Levels/Floof/filelist.xml b/AutomatedTesting/Levels/Floof/filelist.xml deleted file mode 100644 index 82409c84cd..0000000000 --- a/AutomatedTesting/Levels/Floof/filelist.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/AutomatedTesting/Levels/Floof/level.pak b/AutomatedTesting/Levels/Floof/level.pak deleted file mode 100644 index e9374fe73f..0000000000 --- a/AutomatedTesting/Levels/Floof/level.pak +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9577257254e5938790ec3445689a9b59bc1715c7f1aaaad81150b9468e72cbfa -size 1346 diff --git a/AutomatedTesting/Levels/Floof/tags.txt b/AutomatedTesting/Levels/Floof/tags.txt deleted file mode 100644 index 0d6c1880e7..0000000000 --- a/AutomatedTesting/Levels/Floof/tags.txt +++ /dev/null @@ -1,12 +0,0 @@ -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 From 15e6d999c2a61f97b56f5b79f4db0e21eac62c8a Mon Sep 17 00:00:00 2001 From: John Date: Wed, 22 Sep 2021 16:53:01 +0100 Subject: [PATCH 23/50] Remove line breaks and forward declare class. Signed-off-by: John --- .../EditorInteractionSystemComponent.h | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h index 7bbc0ee009..856fd2e326 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h @@ -12,17 +12,9 @@ #include #include - - - - - - -#include - namespace AzToolsFramework { - //class ViewportEditorModeTracker; + class ViewportEditorModeTracker; //! System Component to wrap active input handler. //! EditorInteractionSystemComponent is notified of viewport mouse events from RenderViewport From a94f7c222dee3317d942292b60041051ad0e7202 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 27 Sep 2021 09:23:26 +0100 Subject: [PATCH 24/50] Remove constructors without ViewportEditorModeTrackerInterface ptr. Signed-off-by: John --- .../ComponentMode/ComponentModeCollection.cpp | 10 ++------- .../ComponentMode/ComponentModeCollection.h | 3 +-- .../UnitTest/AzToolsFrameworkTestHelpers.h | 2 +- .../EditorDefaultSelection.cpp | 22 +++++-------------- .../EditorDefaultSelection.h | 3 +-- .../EditorPickEntitySelection.cpp | 18 +++------------ .../EditorPickEntitySelection.h | 3 +-- ...EditorTransformComponentSelectionTests.cpp | 2 +- 8 files changed, 16 insertions(+), 47 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp index dddaa679bf..4d849466ee 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp @@ -218,10 +218,7 @@ namespace AzToolsFramework // this call to activate the component mode editor state should eventually replace the bus call in // ComponentModeCollection::BeginComponentMode() to EditorComponentModeNotifications::EnteredComponentMode // such that all of the notifications for activating/deactivating the different editor modes are in a central location - if (m_viewportEditorModeTracker) - { - m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); - } + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); // enable actions for the first/primary ComponentMode // note: if multiple ComponentModes are activated at the same time, actions @@ -299,10 +296,7 @@ namespace AzToolsFramework // this call to deactivate the component mode editor state should eventually replace the bus call in // ComponentModeCollection::EndComponentMode() to EditorComponentModeNotifications::LeftComponentMode // such that all of the notifications for activating/deactivating the different editor modes are in a central location - if (m_viewportEditorModeTracker) - { - m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); - } + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); // clear stored modes and builders for this ComponentMode // TLDR: avoid 'use after free' error diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h index b295d6103b..9e299d2323 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h @@ -26,8 +26,7 @@ namespace AzToolsFramework AZ_CLASS_ALLOCATOR_DECL /// @cond - ComponentModeCollection() = default; - ComponentModeCollection(ViewportEditorModeTrackerInterface* viewportEditorModeTracker); + explicit ComponentModeCollection(ViewportEditorModeTrackerInterface* viewportEditorModeTracker); ~ComponentModeCollection() = default; ComponentModeCollection(const ComponentModeCollection&) = delete; ComponentModeCollection& operator=(const ComponentModeCollection&) = delete; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h index a67562af76..c4aefecce5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h @@ -172,7 +172,7 @@ namespace UnitTest { // create the default viewport (handles ComponentMode) AZStd::unique_ptr defaultSelection = - AZStd::make_unique(entityDataCache); + AZStd::make_unique(entityDataCache, viewportEditorModeTracker); // override the phantom widget so we can use out custom test widget defaultSelection->SetOverridePhantomWidget(&m_editorActions.m_componentModeWidget); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp index 321549585a..30958cfbc1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp @@ -20,36 +20,26 @@ namespace AzToolsFramework { AZ_CLASS_ALLOCATOR_IMPL(EditorDefaultSelection, AZ::SystemAllocator, 0) - EditorDefaultSelection::EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache) + EditorDefaultSelection::EditorDefaultSelection( + const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) : m_phantomWidget(nullptr) , m_entityDataCache(entityDataCache) + , m_viewportEditorModeTracker(viewportEditorModeTracker) + , m_componentModeCollection(viewportEditorModeTracker) { ActionOverrideRequestBus::Handler::BusConnect(GetEntityContextId()); ComponentModeFramework::ComponentModeSystemRequestBus::Handler::BusConnect(); m_manipulatorManager = AZStd::make_shared(AzToolsFramework::g_mainManipulatorManagerId); m_transformComponentSelection = AZStd::make_unique(entityDataCache); - } - - EditorDefaultSelection::EditorDefaultSelection( - const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) - : EditorDefaultSelection(entityDataCache) - { - m_viewportEditorModeTracker = viewportEditorModeTracker; - if (m_viewportEditorModeTracker) - { - m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default); - } + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default); } EditorDefaultSelection::~EditorDefaultSelection() { ComponentModeFramework::ComponentModeSystemRequestBus::Handler::BusDisconnect(); ActionOverrideRequestBus::Handler::BusDisconnect(); - if (m_viewportEditorModeTracker) - { - m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default); - } + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default); } void EditorDefaultSelection::SetOverridePhantomWidget(QWidget* phantomOverrideWidget) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h index 6a53a2b186..e4c794e99e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h @@ -27,8 +27,7 @@ namespace AzToolsFramework AZ_CLASS_ALLOCATOR_DECL //! @cond - explicit EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache); - explicit EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker); + EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker); EditorDefaultSelection(const EditorDefaultSelection&) = delete; EditorDefaultSelection& operator=(const EditorDefaultSelection&) = delete; virtual ~EditorDefaultSelection(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp index 9306deb69d..1e0f42d01a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp @@ -16,20 +16,11 @@ namespace AzToolsFramework { AZ_CLASS_ALLOCATOR_IMPL(EditorPickEntitySelection, AZ::SystemAllocator, 0) - EditorPickEntitySelection::EditorPickEntitySelection(const EditorVisibleEntityDataCache* entityDataCache) - : m_editorHelpers(AZStd::make_unique(entityDataCache)) - { - } - EditorPickEntitySelection::EditorPickEntitySelection( const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) - : EditorPickEntitySelection(entityDataCache) + : m_editorHelpers(AZStd::make_unique(entityDataCache)) + , m_viewportEditorModeTracker(viewportEditorModeTracker) { - m_viewportEditorModeTracker = viewportEditorModeTracker; - if (m_viewportEditorModeTracker) - { - m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick); - } } EditorPickEntitySelection::~EditorPickEntitySelection() @@ -39,10 +30,7 @@ namespace AzToolsFramework ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetEntityHighlighted, m_hoveredEntityId, false); } - if (m_viewportEditorModeTracker) - { - m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick); - } + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick); } // note: entityIdUnderCursor is the authoritative entityId we get each frame by querying diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h index 511111743a..62fa4161b7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h @@ -22,8 +22,7 @@ namespace AzToolsFramework public: AZ_CLASS_ALLOCATOR_DECL - explicit EditorPickEntitySelection(const EditorVisibleEntityDataCache* entityDataCache); - explicit EditorPickEntitySelection( + EditorPickEntitySelection( const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker); ~EditorPickEntitySelection(); diff --git a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp index 1316523f29..b6170e4b89 100644 --- a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp @@ -346,7 +346,7 @@ namespace UnitTest [](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache, [[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker) { - return AZStd::make_unique(entityDataCache); + return AZStd::make_unique(entityDataCache, viewportEditorModeTracker); }); // When From 5ebe66c5b686b820b80c38b0be8a29240285cdb6 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 27 Sep 2021 13:10:47 +0100 Subject: [PATCH 25/50] Add integration tests for viewport editor modes. Signed-off-by: John --- .../EditorPickEntitySelection.cpp | 1 + .../Viewport/ViewportEditorModeTests.cpp | 111 +++++++++++++----- 2 files changed, 84 insertions(+), 28 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp index 1e0f42d01a..18eda140a0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp @@ -21,6 +21,7 @@ namespace AzToolsFramework : m_editorHelpers(AZStd::make_unique(entityDataCache)) , m_viewportEditorModeTracker(viewportEditorModeTracker) { + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick); } EditorPickEntitySelection::~EditorPickEntitySelection() diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index b2b75e22a7..371bfb2648 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -7,7 +7,9 @@ */ #include +#include #include +#include #include namespace UnitTest @@ -18,6 +20,7 @@ namespace UnitTest using ViewportEditorModeInfo = AzToolsFramework::ViewportEditorModeInfo; using ViewportId = ViewportEditorModeInfo::IdType; using ViewportEditorModesInterface = AzToolsFramework::ViewportEditorModesInterface; + using ViewportEditorModeTrackerInterface = AzToolsFramework::ViewportEditorModeTrackerInterface; void ActivateModeAndExpectSuccess(ViewportEditorModes& editorModeState, ViewportEditorMode mode) { @@ -47,6 +50,26 @@ namespace UnitTest } } + void ExpectOnlyModeActive(const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) + { + for (auto modeIndex = 0; modeIndex < ViewportEditorModes::NumEditorModes; modeIndex++) + { + const auto currentMode = static_cast(modeIndex); + const bool expectedActive = (mode == currentMode); + EXPECT_EQ(editorModeState.IsModeActive(currentMode), expectedActive); + } + } + + void ExpectOnlyModeInactive(const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) + { + for (auto modeIndex = 0; modeIndex < ViewportEditorModes::NumEditorModes; modeIndex++) + { + const auto currentMode = static_cast(modeIndex); + const bool expectedActive = (mode != currentMode); + EXPECT_EQ(editorModeState.IsModeActive(currentMode), expectedActive); + } + } + // Fixture for testing editor mode states class ViewportEditorModesTestsFixture : public ::testing::Test @@ -116,7 +139,7 @@ namespace UnitTest m_editorModes[mode].m_onEnter = true; } - virtual void OnEditorModeDeactivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override + void OnEditorModeDeactivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override { m_editorModes[mode].m_onExit = true; } @@ -156,6 +179,16 @@ namespace UnitTest class ViewportEditorModeTrackerIntegrationTestFixture : public ToolsApplicationFixture { + public: + void SetUpEditorFixtureImpl() override + { + m_viewportEditorModeTracker = AZ::Interface::Get(); + ASSERT_NE(m_viewportEditorModeTracker, nullptr); + m_viewportEditorModes = m_viewportEditorModeTracker->GetViewportEditorModes({}); + } + + ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; + const ViewportEditorModesInterface* m_viewportEditorModes = nullptr; }; TEST_F(ViewportEditorModesTestsFixture, NumberOfEditorModesIsEqualTo4) @@ -174,38 +207,14 @@ namespace UnitTest TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeActiveActivatesOnlyThatMode) { ActivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode); - - for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) - { - const auto editorMode = static_cast(mode); - if (editorMode == m_selectedEditorMode) - { - EXPECT_TRUE(m_editorModes.IsModeActive(static_cast(editorMode))); - } - else - { - EXPECT_FALSE(m_editorModes.IsModeActive(static_cast(editorMode))); - } - } + ExpectOnlyModeActive(m_editorModes, m_selectedEditorMode); } TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeInactiveInactivatesOnlyThatMode) { SetAllModesActive(m_editorModes); DeactivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode); - - for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) - { - const auto editorMode = static_cast(mode); - if (editorMode == m_selectedEditorMode) - { - EXPECT_FALSE(m_editorModes.IsModeActive(editorMode)); - } - else - { - EXPECT_TRUE(m_editorModes.IsModeActive(editorMode)); - } - } + ExpectOnlyModeInactive(m_editorModes, m_selectedEditorMode); } TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingMultipleModesActiveActivatesAllThoseModesNonMutuallyExclusively) @@ -502,7 +511,53 @@ namespace UnitTest } } - TEST_F(ViewportEditorModeTrackerIntegrationTestFixture, FOO) + TEST_F(ViewportEditorModeTrackerIntegrationTestFixture, InitialViewportEditorModeIsDefault) { + ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Default); } + + TEST_F( + ViewportEditorModeTrackerIntegrationTestFixture, EnteringComponentModeAfterInitialStateHasViewportEditorModesDefaultAndComponentModeActive) + { + // When component mode is entered + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast( + &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::BeginComponentMode, + AZStd::vector{}); + + bool inComponentMode = false; + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::BroadcastResult( + inComponentMode, &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::InComponentMode); + + // Expect to be in component mode + EXPECT_TRUE(inComponentMode); + + // Expect the default and component viewport editor modes to be active + EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default)); + EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Component)); + + // ExpeDo not expect ct the pick and focus viewport editor modes to be active + EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Pick)); + EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Focus)); + } + + TEST_F( + ViewportEditorModeTrackerIntegrationTestFixture, + EnteringEditorPickEntitySelectionAfterInitialStateHasOnlyViewportEditorModePickModeActive) + { + // When entering pick mode + using AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus; + EditorInteractionSystemViewportSelectionRequestBus::Event( + AzToolsFramework::GetEntityContextId(), &EditorInteractionSystemViewportSelectionRequestBus::Events::SetHandler, + [](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache, + [[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker) + { + return AZStd::make_unique(entityDataCache, viewportEditorModeTracker); + }); + + // Expect only the pick viewport editor mode to be active + ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Pick); + } + + // FocusMode integration tests will follow (LYN-6995) + } // namespace UnitTest From 36102a75f2cc852215285725840895cb04d6ecc8 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Mon, 27 Sep 2021 21:24:05 -0500 Subject: [PATCH 26/50] Material Editor: Added alternate skybox toggle to the toolbar Signed-off-by: Guthrie Adams --- .../Code/Source/Window/Icons/skybox.svg | 15 +++++++++++++++ .../Code/Source/Window/MaterialEditor.qrc | 1 + .../Window/ToolBar/MaterialEditorToolBar.cpp | 15 ++++++++++++++- .../Source/Window/ToolBar/MaterialEditorToolBar.h | 2 ++ 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/Icons/skybox.svg diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/Icons/skybox.svg b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/Icons/skybox.svg new file mode 100644 index 0000000000..83df996198 --- /dev/null +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/Icons/skybox.svg @@ -0,0 +1,15 @@ + + + + icon / Environmental / Sky Highlight + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditor.qrc b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditor.qrc index cde48079ac..902201e792 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditor.qrc +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditor.qrc @@ -19,6 +19,7 @@ Icons/texture_edit.png Icons/grid.svg Icons/shadow.svg + Icons/skybox.svg Icons/toneMapping.svg Icons/View.svg diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/MaterialEditorToolBar.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/MaterialEditorToolBar.cpp index 55829fd744..1e189168da 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/MaterialEditorToolBar.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/MaterialEditorToolBar.cpp @@ -50,8 +50,16 @@ namespace MaterialEditor }); m_toggleShadowCatcher->setChecked(viewportSettings->m_enableShadowCatcher); - // Add mapping selection button + // Add toggle alternate skybox button + m_toggleAlternateSkybox = addAction(QIcon(":/Icons/skybox.svg"), "Toggle Alternate Skybox"); + m_toggleAlternateSkybox->setCheckable(true); + connect(m_toggleAlternateSkybox, &QAction::triggered, [this]() { + MaterialViewportRequestBus::Broadcast( + &MaterialViewportRequestBus::Events::SetAlternateSkyboxEnabled, m_toggleAlternateSkybox->isChecked()); + }); + m_toggleAlternateSkybox->setChecked(viewportSettings->m_enableAlternateSkybox); + // Add mapping selection button QToolButton* toneMappingButton = new QToolButton(this); QMenu* toneMappingMenu = new QMenu(toneMappingButton); @@ -105,6 +113,11 @@ namespace MaterialEditor m_toggleGrid->setChecked(enable); } + void MaterialEditorToolBar::OnAlternateSkyboxEnabledChanged(bool enable) + { + m_toggleAlternateSkybox->setChecked(enable); + } + void MaterialEditorToolBar::OnDisplayMapperOperationTypeChanged(AZ::Render::DisplayMapperOperationType operationType) { for (auto operationActionPair : m_operationActions) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/MaterialEditorToolBar.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/MaterialEditorToolBar.h index d68c23665f..c25b90eb80 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/MaterialEditorToolBar.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/MaterialEditorToolBar.h @@ -29,10 +29,12 @@ namespace MaterialEditor // MaterialViewportNotificationBus::Handler overrides... void OnShadowCatcherEnabledChanged([[maybe_unused]] bool enable) override; void OnGridEnabledChanged([[maybe_unused]] bool enable) override; + void OnAlternateSkyboxEnabledChanged([[maybe_unused]] bool enable) override; void OnDisplayMapperOperationTypeChanged(AZ::Render::DisplayMapperOperationType operationType) override; QAction* m_toggleGrid = {}; QAction* m_toggleShadowCatcher = {}; + QAction* m_toggleAlternateSkybox = {}; AZStd::unordered_map m_operationNames; AZStd::unordered_map m_operationActions; From 75e7758eedab7142137fd816a6e8a3971655bbd7 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 28 Sep 2021 08:57:14 +0100 Subject: [PATCH 27/50] Address PR comments. Signed-off-by: John --- .../EditorInteractionSystemComponent.cpp | 12 ++++-------- .../Tests/Viewport/ViewportEditorModeTests.cpp | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp index 7f84038ace..5d03231aab 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp @@ -17,19 +17,15 @@ namespace AzToolsFramework EditorInteractionSystemComponent::EditorInteractionSystemComponent() : m_viewportEditorMode(AZStd::make_unique()) { - if (AZ::Interface::Get() == nullptr) - { - AZ::Interface::Register(m_viewportEditorMode.get()); - } + AZ_Assert(AZ::Interface::Get() == nullptr, "Unexpected registration of viewport editor mode tracker.") + AZ::Interface::Register(m_viewportEditorMode.get()); } EditorInteractionSystemComponent::~EditorInteractionSystemComponent() { m_interactionRequests.reset(); - if (AZ::Interface::Get() != nullptr) - { - AZ::Interface::Unregister(m_viewportEditorMode.get()); - } + AZ_Assert(AZ::Interface::Get() != nullptr, "Unexpected unregistration of viewport editor mode tracker.") + AZ::Interface::Unregister(m_viewportEditorMode.get()); } void EditorInteractionSystemComponent::Activate() diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 371bfb2648..866d88b7ba 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -535,7 +535,7 @@ namespace UnitTest EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default)); EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Component)); - // ExpeDo not expect ct the pick and focus viewport editor modes to be active + // Do not expect the pick and focus viewport editor modes to be active EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Pick)); EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Focus)); } From 25b16fc82cc1569bf09deb6b4313d42b1d75d743 Mon Sep 17 00:00:00 2001 From: dmcdiar Date: Tue, 28 Sep 2021 12:25:07 -0700 Subject: [PATCH 28/50] Changed the DiffuseProbeGrid to an OBB Signed-off-by: dmcdiar --- .../DiffuseProbeGrid.cpp | 29 +++++++++++-------- .../DiffuseProbeGrid.h | 10 +++---- .../DiffuseProbeGridFeatureProcessor.cpp | 9 +++--- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp index 4d58948b98..a966eaddcb 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp @@ -128,8 +128,8 @@ namespace AZ void DiffuseProbeGrid::SetTransform(const AZ::Transform& transform) { - m_position = transform.GetTranslation(); - m_aabbWs = Aabb::CreateCenterHalfExtents(m_position, m_extents / 2.0f); + m_transform = transform; + m_obbWs = Obb::CreateFromPositionRotationAndHalfLengths(m_transform.GetTranslation(), m_transform.GetRotation(), m_extents / 2.0f); // probes need to be relocated since the grid position changed m_remainingRelocationIterations = DefaultNumRelocationIterations; @@ -145,7 +145,7 @@ namespace AZ void DiffuseProbeGrid::SetExtents(const AZ::Vector3& extents) { m_extents = extents; - m_aabbWs = Aabb::CreateCenterHalfExtents(m_position, m_extents / 2.0f); + m_obbWs = Obb::CreateFromPositionRotationAndHalfLengths(m_transform.GetTranslation(), m_transform.GetRotation(), m_extents / 2.0f); // recompute the number of probes since the extents changed UpdateProbeCount(); @@ -467,7 +467,10 @@ namespace AZ RHI::ShaderInputConstantIndex constantIndex; constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_probeGrid.origin")); - srg->SetConstant(constantIndex, m_position); + srg->SetConstant(constantIndex, m_transform.GetTranslation()); + + constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_probeGrid.rotation")); + srg->SetConstant(constantIndex, m_transform.GetRotation()); constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_probeGrid.numRaysPerProbe")); srg->SetConstant(constantIndex, m_numRaysPerProbe); @@ -760,14 +763,15 @@ namespace AZ RHI::ShaderInputImageIndex imageIndex; constantIndex = srgLayout->FindShaderInputConstantIndex(Name("m_modelToWorld")); - AZ::Matrix3x4 modelToWorld = AZ::Matrix3x4::CreateFromMatrix3x3AndTranslation(Matrix3x3::CreateIdentity(), m_position) * AZ::Matrix3x4::CreateScale(m_extents); + AZ::Matrix3x4 modelToWorld = AZ::Matrix3x4::CreateFromTransform(m_transform) * AZ::Matrix3x4::CreateScale(m_extents); m_renderObjectSrg->SetConstant(constantIndex, modelToWorld); - constantIndex = srgLayout->FindShaderInputConstantIndex(Name("m_aabbMin")); - m_renderObjectSrg->SetConstant(constantIndex, m_aabbWs.GetMin()); + constantIndex = srgLayout->FindShaderInputConstantIndex(Name("m_modelToWorldInverse")); + AZ::Matrix3x4 modelToWorldInverse = AZ::Matrix3x4::CreateFromTransform(m_transform).GetInverseFull(); + m_renderObjectSrg->SetConstant(constantIndex, modelToWorldInverse); - constantIndex = srgLayout->FindShaderInputConstantIndex(Name("m_aabbMax")); - m_renderObjectSrg->SetConstant(constantIndex, m_aabbWs.GetMax()); + constantIndex = srgLayout->FindShaderInputConstantIndex(Name("m_obbHalfLengths")); + m_renderObjectSrg->SetConstant(constantIndex, m_obbWs.GetHalfLengths()); constantIndex = srgLayout->FindShaderInputConstantIndex(Name("m_enableDiffuseGI")); m_renderObjectSrg->SetConstant(constantIndex, m_enabled); @@ -821,13 +825,14 @@ namespace AZ lod.m_screenCoverageMax = 1.0f; // update cullable bounds + Aabb aabbWs = Aabb::CreateFromObb(m_obbWs); Vector3 center; float radius; - m_aabbWs.GetAsSphere(center, radius); + aabbWs.GetAsSphere(center, radius); m_cullable.m_cullData.m_boundingSphere = Sphere(center, radius); - m_cullable.m_cullData.m_boundingObb = m_aabbWs.GetTransformedObb(AZ::Transform::CreateIdentity()); - m_cullable.m_cullData.m_visibilityEntry.m_boundingVolume = m_aabbWs; + m_cullable.m_cullData.m_boundingObb = aabbWs.GetTransformedObb(AZ::Transform::CreateIdentity()); + m_cullable.m_cullData.m_visibilityEntry.m_boundingVolume = aabbWs; m_cullable.m_cullData.m_visibilityEntry.m_userData = &m_cullable; m_cullable.m_cullData.m_visibilityEntry.m_typeFlags = AzFramework::VisibilityEntry::TYPE_RPI_Cullable; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h index 89e7173dd5..97c336ed41 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h @@ -72,7 +72,7 @@ namespace AZ const AZ::Vector3& GetExtents() const { return m_extents; } void SetExtents(const AZ::Vector3& extents); - const AZ::Aabb& GetAabbWs() const { return m_aabbWs; } + const AZ::Obb& GetObbWs() const { return m_obbWs; } bool ValidateProbeSpacing(const AZ::Vector3& newSpacing); const AZ::Vector3& GetProbeSpacing() const { return m_probeSpacing; } @@ -183,14 +183,14 @@ namespace AZ // scene RPI::Scene* m_scene = nullptr; - // probe grid position - AZ::Vector3 m_position = AZ::Vector3(0.0f, 0.0f, 0.0f); + // probe grid transform + AZ::Transform m_transform = AZ::Transform::CreateIdentity(); // extents of the probe grid AZ::Vector3 m_extents = AZ::Vector3(0.0f, 0.0f, 0.0f); - // probe grid AABB (world space), built from position and extents - AZ::Aabb m_aabbWs = AZ::Aabb::CreateNull(); + // probe grid OBB (world space), built from transform and extents + AZ::Obb m_obbWs; // per-axis spacing of probes in the grid AZ::Vector3 m_probeSpacing; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp index d79240d4f1..4329fd556c 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp @@ -154,10 +154,11 @@ namespace AZ // sort the probes by descending inner volume size, so the smallest volumes are rendered last auto sortFn = [](AZStd::shared_ptr const& probe1, AZStd::shared_ptr const& probe2) -> bool { - const Aabb& aabb1 = probe1->GetAabbWs(); - const Aabb& aabb2 = probe2->GetAabbWs(); - float size1 = aabb1.GetXExtent() * aabb1.GetZExtent() * aabb1.GetYExtent(); - float size2 = aabb2.GetXExtent() * aabb2.GetZExtent() * aabb2.GetYExtent(); + const Obb& obb1 = probe1->GetObbWs(); + const Obb& obb2 = probe2->GetObbWs(); + float size1 = obb1.GetHalfLengthX() * obb1.GetHalfLengthZ() * obb1.GetHalfLengthY(); + float size2 = obb2.GetHalfLengthX() * obb2.GetHalfLengthZ() * obb2.GetHalfLengthY(); + return (size1 > size2); }; From 615b53df50785b5a96f80d18cd805282af233441 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 29 Sep 2021 16:26:14 -0700 Subject: [PATCH 29/50] fix bad unused variable component property check Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Builder/ScriptCanvasBuilder.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp index 9c3cdca3e8..5e97bf4aec 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp @@ -181,12 +181,15 @@ namespace ScriptCanvasBuilder continue; } - // copy to override unused list for editor display - m_overridesUnused.push_back(*graphVariable); - auto& overrideValue = m_overridesUnused.back(); - overrideValue.DeepCopy(*graphVariable); - overrideValue.SetScriptInputControlVisibility(AZ::Edit::PropertyVisibility::Hide); - overrideValue.SetAllowSignalOnChange(false); + if (graphVariable->IsComponentProperty()) + { + // copy to override unused list for editor display + m_overridesUnused.push_back(*graphVariable); + auto& overrideValue = m_overridesUnused.back(); + overrideValue.DeepCopy(*graphVariable); + overrideValue.SetScriptInputControlVisibility(AZ::Edit::PropertyVisibility::Hide); + overrideValue.SetAllowSignalOnChange(false); + } } } From cfbe76fdf639814abb92ad8d1ea30c5b21042165 Mon Sep 17 00:00:00 2001 From: John Date: Thu, 30 Sep 2021 17:29:32 +0100 Subject: [PATCH 30/50] Add call site for activating/deactivating Focus. Signed-off-by: John --- .../FocusMode/FocusModeSystemComponent.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp index e1c04fcb93..3fafb4db81 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp @@ -10,6 +10,7 @@ #include #include +#include namespace AzToolsFramework { @@ -66,7 +67,18 @@ namespace AzToolsFramework { m_focusRoot = entityId; - // TODO - If m_focusRoot != AZ::EntityId(), activate focus mode via ViewportEditorModeTrackerInterface; else, deactivate focus mode + if (auto tracker = AZ::Interface::Get(); + tracker != nullptr) + { + if (!m_focusRoot.IsValid() && entityId.IsValid()) + { + tracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Focus); + } + else if (m_focusRoot.IsValid() && !entityId.IsValid()) + { + tracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Focus); + } + } } void FocusModeSystemComponent::ClearFocusRoot() From 5fe4d8043d70a23f55d081dcfd4097d45ebcec95 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Thu, 30 Sep 2021 12:55:41 -0700 Subject: [PATCH 31/50] set ed_useNewAssetBrowserTableView to false by default Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../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 c6772ea2d7..acf935e6dc 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, true, nullptr, AZ::ConsoleFunctorFlags::Null, + bool, ed_useNewAssetBrowserTableView, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Use the new AssetBrowser TableView for searching assets."); namespace AzToolsFramework { From 6e115fb25730899472a0ccb1be6f1ea745276df8 Mon Sep 17 00:00:00 2001 From: dmcdiar Date: Thu, 30 Sep 2021 14:20:05 -0700 Subject: [PATCH 32/50] Updated RTX-GI SDK to v1.1.30. Signed-off-by: dmcdiar --- .../diffuseprobegridblenddistance.azshader | Bin 90350 -> 77447 bytes ...begridblenddistance_dx12_0.azshadervariant | Bin 8186 -> 8258 bytes ...begridblenddistance_null_0.azshadervariant | Bin 486 -> 486 bytes ...gridblenddistance_vulkan_0.azshadervariant | Bin 8218 -> 8286 bytes .../diffuseprobegridblendirradiance.azshader | Bin 90394 -> 77491 bytes ...gridblendirradiance_dx12_0.azshadervariant | Bin 8646 -> 9034 bytes ...gridblendirradiance_null_0.azshadervariant | Bin 486 -> 486 bytes ...idblendirradiance_vulkan_0.azshadervariant | Bin 9394 -> 10002 bytes ...iffuseprobegridborderupdatecolumn.azshader | Bin 28300 -> 27583 bytes ...dborderupdatecolumn_dx12_0.azshadervariant | Bin 4522 -> 4522 bytes ...dborderupdatecolumn_null_0.azshadervariant | Bin 486 -> 486 bytes ...orderupdatecolumn_vulkan_0.azshadervariant | Bin 2701 -> 2701 bytes .../diffuseprobegridborderupdaterow.azshader | Bin 28297 -> 27580 bytes ...gridborderupdaterow_dx12_0.azshadervariant | Bin 4338 -> 4338 bytes ...gridborderupdaterow_null_0.azshadervariant | Bin 486 -> 486 bytes ...idborderupdaterow_vulkan_0.azshadervariant | Bin 2222 -> 2222 bytes .../diffuseprobegridclassification.azshader | Bin 87855 -> 74952 bytes ...egridclassification_dx12_0.azshadervariant | Bin 6122 -> 6166 bytes ...egridclassification_null_0.azshadervariant | Bin 486 -> 486 bytes ...ridclassification_vulkan_0.azshadervariant | Bin 4898 -> 4962 bytes .../diffuseprobegridraytracing.azshader | Bin 160607 -> 142100 bytes ...probegridraytracing_dx12_0.azshadervariant | Bin 30714 -> 31950 bytes ...probegridraytracing_null_0.azshadervariant | Bin 486 -> 486 bytes ...obegridraytracing_vulkan_0.azshadervariant | Bin 32316 -> 34448 bytes ...fuseprobegridraytracingclosesthit.azshader | Bin 160617 -> 142110 bytes ...aytracingclosesthit_dx12_0.azshadervariant | Bin 13126 -> 13094 bytes ...aytracingclosesthit_null_0.azshadervariant | Bin 486 -> 486 bytes ...tracingclosesthit_vulkan_0.azshadervariant | Bin 5404 -> 5404 bytes .../diffuseprobegridraytracingmiss.azshader | Bin 160611 -> 142104 bytes ...egridraytracingmiss_dx12_0.azshadervariant | Bin 13202 -> 13262 bytes ...egridraytracingmiss_null_0.azshadervariant | Bin 486 -> 486 bytes ...ridraytracingmiss_vulkan_0.azshadervariant | Bin 6348 -> 6396 bytes .../diffuseprobegridrelocation.azshader | Bin 91763 -> 77960 bytes ...probegridrelocation_dx12_0.azshadervariant | Bin 8006 -> 8046 bytes ...probegridrelocation_null_0.azshadervariant | Bin 486 -> 486 bytes ...obegridrelocation_vulkan_0.azshadervariant | Bin 9298 -> 9442 bytes .../diffuseprobegridrender.azshader | Bin 231825 -> 203892 bytes ...fuseprobegridrender_dx12_0.azshadervariant | Bin 29467 -> 30799 bytes ...fuseprobegridrender_null_0.azshadervariant | Bin 589 -> 589 bytes ...seprobegridrender_vulkan_0.azshadervariant | Bin 20213 -> 22565 bytes 40 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance.azshader index 596f9a383eb7adc32a15e4712b7238c0188e8246..31fae5d98bb261ee35faac2489e4138379a5b952 100644 GIT binary patch delta 3899 zcmeH~Uu;uV9LMw1t}L=~*BPO7bh`_%sR{R9Y0buPD+qB#lC5qd5}jRJ{v<=CGACJ# z4;z@2Eh^<_@J48GCcR5Hp2vnCK?~? z)A{}G@7&+{<(zMR=W{ZX1(BQJZe%pp5A5)PA#6NMM*W*Rt$P=^^l_fze9MP!Vw4(hA8pcIj z9;l(+p!y)v?^a`Oz)r8QYZh|x#T5*X*P`T1h-oU-Vxdt~6?khOrJutC0CxK`N#q@u3sphZRT{RmcMsI2Ko!x|EkVJTBw(P6e6IdAZZiAX8~9 zyd2ApD@^MkE55m`6@Jk+zhdZ8>vh;%gN2j7e>^(%NWnn_PnKiKbviFCL-2WN{e#kC z@$J;1Tfd#5Y*T_%v=&RRtmA52G4^~D$y9hMJbJZjRpJf(%HHA!@2x?k-D~s{BklPX zmv3=@x5Z86rIo)u|ApK0ue7+6v-I9|#XX|GJrgRmy?!r(Gg{o(`%d!bdK~YV38Zgv z5bEnR$2$_8!wfA_o!jtlCp+^4r-#S0WXBOu+88Sp^KPR%F;5Vluoo#$_=5C=Eoe{J zIpPbVCi(e<Sci-I+(%WBpX620^KG5Hp*=S?Q0BL^!aMCX9 delta 6120 zcmeI0Urbw79LG5b2yW0825US1l)%7j&|9Dxe+T8yNRfXX12Yqa(hU-nv5r3z7n2b) zhl>ks^4+{92B=DWmy^LvL(Ks--l#a4uErJs7GNGr?fj~txEc>EF=QI2!AqT#BJ!(6GBP2iNO9c|hY)R#J72$sRHpohgW zz-IUro#@rGB&b#UVOz|>m;92S2kqDApjAJJ#Vf?c9X#f+ji zmI-_oWBH5~VwvCVJd=r(8smGrdA(nsfRXb#xcUNdXx=MW%-|iJKMmCdsY)lhHOz>{ zG(oh-G8-0B`J-zq;aL)Vr5ExUlHU>dsM9f9&*!>Y;BPJ!_DmyOyqn;1GlGYtr`KYH zkHK@XUUX_%m>9O3y@C1~fxpqinEY89jWqfBJ7PklpS8w$?KlkGN7+uWfQkRBqI676 ztR_w*P9!!E8;G-rvxrT^CSo(OnYe(sfVhOXgxErCA+92>BDNA+iR*~#h;76+;%4Gz zVmq;&*hB0go*01LN``a)q_T3Am8+~=W~T-8uUNUhlBS|i zIeX$!?q1Qmhh@jpzUg+YOb%rq(R>vAivhr5(ytt4wDS^u-idRAGrN}^U0^?y83N4=k{UvZt#pAEU5n8b=TKH+u-OCJ8a za_t+NeQQmu`KN&wrn|-P*Qv3(vyQWI-Lpk?1X~yFocTUD@1}9dHq$MeqAiszPsz6D z!Mbec%(t(pW)_!jsr00JpQx53+ceLGn#^17aEpD*6`KaWRwfIV`A;S;S8lO!Ir2>% z*Te9jlPkFt!P82fx-iOhT<&09$))%Mwec9WXxG%-t>bF${C2CF^D_lLQ?j1R%_UQo zHGQMJq3d!@pu)JO?Q&~-N(cb^sNH_9^2+Afsoyj)b;(fA?e%W GHO(J_{C1uI diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_dx12_0.azshadervariant index 8481bdb15bfb4b6e4cdf4329b8539d31b98fefb1..19e9fdfc8d23db9d1ac4b062b395258ab3eeb219 100644 GIT binary patch delta 4032 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 delta 3931 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 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance.azshader index fc11f9de64abcf032720d6e9712b883fb705b387..0025388bc13bae5830f46f3b79be2b4a3a0800ba 100644 GIT binary patch delta 4099 zcmeH~U2Icj7{_@=*{0ahgM6G8x0bOF8Cg%amME@ZVRMY&wz_dK6zy8UWFoZLCLxQ_ zVRg#{*RKC=G zd{1>47wxDYG0-k_jd+l8I5DrQ(;`|X(r#?tWcT@&LbsxjTs&9}%d{rGFxTNH5k10d z?$)8;h=`CV*I9wsIWvA8ji>SX^3m|VNEi5vofL-9>0?z3$pr6c8CH2#A>uiRll;2N z>y;-oWI&gBE4-CTywG(U)`-L_t-@wh3Ycm!mBQ99vEhZpyMIy7o_>T5z!v7Yx2fT(<$IMa z=U1l9>=U{o2DF}1V84GI@3|EldnI3PDf*5|uuLus+A?Sjp@A0_JC}n|zaG(NCBBEN zQF2Vr-V}&`OGP`_^;DA3>ds_Vf%N#HUxKc#5+zK6b!`>Kx+O@r)*!Z4&n6z`kr@MJ zDN7chf5?=6amTHdA57H#gztuW(!1Yk$SGe}`ULYlMp^jUcrq!-q#*wjg8Xtj*#g<$ zUZy$o%VmXCREUp;RtDRvNJr@hGEA+;Sd%qy^%do#_f>A7vZXC)qe&b67i?6E-s7Jp z#h5(PANZO64=nVdnxlPQbNhMkg5arYDiH!#uH}*N#@|6{$92c7n+9SxUZ;DKC>t!M z`6z0_;G}*AN9Az|vk0V`d zT5sOPrPH%qI?hL9zw6^{D#y%cQ=?qxU-`6^84Pqcm<~+Mfho^14@{@+zTD+Zl|mwg znZ1bOgnCe>Q>Hdj98cLNM*5RapSv07Q+C2c|9e1PpJw>x`9n2VrsI72)ia@vqT`FN n%6xh@smr7;AJ~u6y>%Jn9&1jy52F6KGioTV_BYD*x>xuE59Hca delta 6430 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 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_null_0.azshadervariant index 2f2cd5cccff43f5abd9e32854ad3bbe7a994c792..4a2b0e9944d9b41fe3c3c98f4c7607eebe0d3a2d 100644 GIT binary patch delta 16 XcmaFH{ET_SJw}eXU*!~o85kGIT}1fC{K}p^9rMD%M>QYfF)~YTa5y1x5S&-ggIXDSrA#j~UL)Z&YW|D9~{SV z;#M`7x_f_{5&JWf*M8Au%MW!WyY{}h?xNuhwx?e_L|JbZydWyaW!)D(!ZY7 zYv=dRUbiOaosGlF6OSkM8&9q-Qki~HVpf0-`v&B9zQ$g;QO=wituxT z{!`w&6XEbJnc?C}Y6px>cV=4(vG=E8;u* zo!2gCJvn{z;Rnm6jy%4nKEK_J4R6n^ADZ)W{@%x1lpZ;>W5ei#6MLS_{<7nYI%iIw zk?$TkLowsDqmIw*O@8M6_A5hQ6ldJhzJAc0I| zdu)tr*u9D4G*CH{o%u`}Eu4lf(#&b>&N-8dCZ|Pf%F>1nAA~;H(IOg{H+Pyi@tPZo z@&Xm1tRnS^_(r0$oEvkvsme#Px1lLclr{|RusVGy=l; zNp(0B45UfnQO;6xpt>cenO};T&C^j1gfe6v6xA&Ep>_6hU$WmXz<5eEQchspHf?O z%CR|Mp3cyr-(6~RkmD0qUKE6<#p>-0dR zBCwz`SP&@V@>y=&DOazb^ALKEVVlluh+@{ zUgb#UzR(|?MabL_#!_v?|-b9b?)pZ$7d^yGn_J^S^@=*bH` z{lJ>cxxTleyJUu8tOtg_VXOh>_a!b^s>tlvGgyBg#ybE;@0lHWfSvEd*e_Uy596ML zW&1Gp4VLS}xWizReHgU|EAV0L39Q(M(Fb5Nd>DNIHphq22VnDk81(?-;jz7OufVEL z!`L78xjGAS!;adRANLHu9X^b^1@^EH<352s?Zdb~V9)z7?h4pmAI4n)d)33J8v~4y zqizA?yxWQ=$5c^2t~5n%(FPZ#mTG@DfM zV365#74MJJO)?l{xlvDByN7t{gpcWaicgh+$>(}Dwni_>3}k$Ji(cNhZ>-t(k(??r zeP8h<)vE`Y+)uJbhS_r;=|7VPh^GflP7}{vGyj3&<(_W(L6W$4rXP&jSw60{b~Qv? zU-b&}P*ER`A12=Hhl`i}XwG7UIQA4L>aS`ej}&2JWPaxf(@5t$sN*OR7-ZOJ@$@Cs zL0Qrx#Haq$+y*>Ys&W|Pf!N~1-sz7s`E(VI&-t1e*s_nY?i|}kd&%P@)8lp@h?g#6 zpPhwr_tAr;I33;kvv+zO-0DJH@;?({3z-fd)&=wXQ7hI<(dyi1&YC@BXr>Ne)R-JI zMX3#9IgS@kOc#?rOFa7lXAjw$S=;mz#G?nNCKELilRdLuj%I~+apYW2#-^1rnWVX^ ztS`_EPmBxQIhH3ryy@f|t9K(OPdxsti++m7lQ(j{CzB^~foA-v5%N?|rfyb)Lh%U= zV)`OakN+6ikI~GVz%ZG+#6YGmxEl=Q49$FJSQD8V@{J*1WNOCu#boq+TTG^A)KBTS z_S6g=vfYbf@s6|nDU+wUvXg1@bjeFcrnvW)eOx5kwzcm#yE8L93_MM%(SI{VBXoN> z2Xbd{F5gI+rFpEf;CyF`$Pbxwm?I*;uZ7Ol%=lJ(FU|8r_%rA01v*D_iHH~wgMDSH z!kqJb5w&YC;=N}L&OIQSFPf_SIL8GdFot2J;=zb_wP#l*9$R$Sk#A6BYnxrUXTvvT znYXWn;=!-={1%DF7aSY%s1Sjh&&A@2VLpq+;{$F!mEyr|?JDuaA;&AdyhGx#LuYx1 z#gjMtv-s8G!Ts?skqmC}BjSk-zTAr+70(*z%&tZ}c~CR6s}&E9{Z9D~(Of42=ZrY> zOEoi&t0w4{h`=~^_+y&s3uJI&(+Bk;dLc!`e!!M`SgL070{e*wyqm~;mx;$8ot^(> z;yHhM*Yhe<$({!>1*NF$GSHtq-jksO}Zhkk2Cl>u?wYyO~xZiKBWN_-%L-S1{Vu7#luyr0j zO7k@y_A~L|GekFd*v;a>`-!gdu%C+uA1xv`a=k?a&M<7fcrfx!(s^L_3r}vO86RST zZxFQ+#ghZNeBB1>vPHxm(8Y-wi5iONRogf7QSBT1ts?B{Uwo+v z`$o4-#J(qpu(NZz&%+ZnPZNc-N;}Q>i_o#w1DdHZGi#yWE^04g{T-s6F2&C6LGkE` z@s;8|}H2+3~A8!uwBceGXaI<+-Jn?zIuz5^`9k{&*k9+ub z?<{vo2J0!Jmwv06K|bi75P^{oJo~o%!0jD-Qao{LMXbd;wp#?wI~K3`DN$n)?^r9% zPm92?W7zpVBmQZRG`Z))`DQB06wS|y&JwZSIOU9tkFE2Zc>g-jO9r!b>@NRK7&>~0 z*!i0Gh>}GX8yP!(cPP;Odr^{zGwv>8P0oF<2px7)HNPM-yK}{3H%{}5o{n0-B%Wcv z$LteNotbxf=kv07a_J+o@Ae;j8269$UlExt`XsL(UlmV(_Yx6XnsqC&2*97p|{1ec2g00vwcT=YY}?G_KW8|CI;_0G2az| zw-l}NumhgV`sVwdcx=(xd-_N5_@Ohq_r-%lX7?xY*r7|(`@*_^7Lhmkpl>6>#`bkk zJo+voYz_a5htogo(bhdA9^FBa*?u6N81%8<_ON7h2SxTB_^Wtgpd)vB=Wm)B+*8i$ z?;+eO?j@SDB+)Q|Hd22ejT0&CP^?9}!Qi zB=HPlp*u?iMl5*F&*}w^Oij_VCcj5gt7P%)je6KOrMY-;hGA!W7_eb2Jd8VIcd(@} z{IN$*+!b1j{%9qh9>K<+4|!RC(NpY`oT&l1T7S_~_@g5hI=eUY6lY=g#(I|;;7<)( z%YLY4bi+i{iCVVN%%GOo%oPttt(fh;v=!f1I_`|spq*^OiljS7yuAbcC37F>%M{`0kmDtH z5#L0!{SK2V8Ely_hUL&z7&?f-L=L9!CV)I4 z@x%eAZ-;1R(6{J@ioobwc>Dcen0R_%plmIl;ga=p^8LexJ8AyR+#C95gn0b93;0=V zYB*9d^`nmVd%=0)_2d4(Q1rIXQLasFpM#{geU286&h|M*JTbu8=lPl$>=WHs5g7Y~ zx3_GZc-9*%TizViV_^-Q*S;xG)G;9FoaDMrk8Jr)w0udPJ2XDV`O%<;n_e`iCYjK8! z9!?%3McA27k*DJvskiwQdw5UJA3O7z=IMAZScktCj}<>%JUV_~V%>|xgYm8-&k#>s zaQejdz)YWDGgCY<=^gCZpY`G_@$@1#R`=QB!5N0l@i1V+=6V?CW8d0&!tlo)Jw0e| ze2HY<_)_H#&)beYgWUPXQGezWs``0Ue#V*p-IC7o;Vyeu7Oc2_Q`)?OK|3xEF8%aS z{15Z6joZ2{eNN7-@;jb*>v-NnMK5^&D#?v=x{j64{Exbv`ta~$y{q@%b>*gyCl0v1 W(bP{r>~i101liwyG^HzFwtoYb$*W8N literal 9394 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 PifleFYAraqKidERu9p1D diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_dx12_0.azshadervariant index 76f61d2fd4b8b32be070bc090959f040d5239c48..f60c7135977ac8215b5c78551c6f716448afb590 100644 GIT binary patch delta 640 zcmZ3byh?dP2P22_d;uNCpnRsu6BvCAKhHmVOl0v?=17k_P4n41OBfj#7#jE)7}$Wc z1rU1xaRd-&0Pz_h=GiRBbe&z(CBoAuhn;~TiGh{jHc$_U&jh3efJ#Du;!e&7?kVyx zFkG5^k!jE7mt40PZ$c6qw#hG8{4ns;`t_VDO#%kSB_bO>l;S z$Jxn_yrT8n(wR5;oZZC3wn1@$nLtAbqc98O4Tc;EF`nB3Dbj5ZFL`k8Jvnje$KkDG45u&b;O2U|e$IXGf4d1YC73u)&Jy5PnaFH-L#>CW!;xc;U^6p=qd~)? z2bZrUm?$!E!L?1EE1<|IHF>{)n8#^mjl>4QW;US0h<^`w&oS_|Fz`J9B9IO@;g$rG zL;*M9j>IDeKo-sloWX3S&}_1TIZ2?&T*JtMS;8=bL4c)s>10_!B}UK54uVM>bHB=Y IYy!qJ0QEJ|=>Px# delta 642 zcmZ3byh?dP2O~!g@8(;njcS`GPhj*hH4D7=SXy}HSy!9iD-}3Q`xqG*7#jE)7}$Zd z4G{YPaSRaW0PzJN7T{oD(Amt(be-MR!!g)H1SkXo^Cvd@Kkd33d-tp7_VY2e$6O*j zeSCmsBr&iuTn3s6;xhqh0iaqFptzIsfqRNP3=F3>^KwmNl3NY+`~l6g*nl&wTK?ASj)imAjZia z{EO=&+XP(Cb~rLMC`kBRSM-={)n8#&ijl>4QW;US02#1Hf=NR}}82BCl5lDxda7%(o zqJW!lN8*tKAPc2}W-yy6G@GnoP7-J`*D$hRmN3j<5MXIOI$2gwi7{}pgJ2Rc$v^-A Dp@`27 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_null_0.azshadervariant index 2f2cd5cccff43f5abd9e32854ad3bbe7a994c792..3e810bcfb51b320702134c14db816f744549bb72 100644 GIT binary patch delta 16 YcmaFH{ET_SJw}eXU*$YDF)%Oy06p^t6aWAK delta 16 ScmaFH{ET_SJw^@&C;$L0bOUMt diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_vulkan_0.azshadervariant index 8b6ec377a6d8ae0be62e2039f4c523877998bd75..5918f277b577ebd0685c1b784ad68aa7808ff1fc 100644 GIT binary patch delta 16 XcmeAb?G@e7%EdAFtDMIs1_lNIG6V%S delta 16 RcmeAb?G@e7%EiF|1ppz10*n9v diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow.azshader index 9050f9094343d831346b79bd14a9c614d43e3c44..120eb70e545519f0872beaeb7ff920804a40ee2e 100644 GIT binary patch delta 478 zcmeCY%edz{;|3)b*12EheK%}YXW?fQEO)We4=BpdN=+^)*3UOiNu503z=+MoxgfyL zW%Ea#qs(k493A2;88AY#tQ zG3AiqQDcd-n>X`|@e1QLc=AUc<;}kg7NIz4^8>ww_~e3?|QuTrv4;&}Om?*gP-t3ihB| Q5H{bc{T3oF31B&vqQj<%H_4AEWQsawD3sQ^95{ohu z^GYV$^BA#3MCD}$xo)m!J<81L;ph-&x!F<2nUU4QvtVP&Y)U<)Voe^}R`8!Wi!!LqAUe;;YsEEs9Q$dNSfTWo>R zrpC<*qP)VyyJB)ZtMcZV8jEoGYjdOS5)y)lka56ZBGF@D|%l$c><%4;VB9CMl%P;S#7PGE0*l`4`gIuU^v0Yz`zEi zEr8eqh$DbF1BlN6G0SE_rt|EYE)kwSdw^<^7+4wB1NDITOh8%ysALIH+{yXCJw+Y{ zhGmm4GVR&?kn0wsTx$T2GJ|TMfQmaqhqyw50@GVbhC{|c^_3C~3_g=@@XP zILne4Va9QKb7JI-v`Dr?g)$k=0=@#<(wR5;oZZC3wn1@$nLtAbqc98O4Tc;EF`nB3 zDbj5ZFG+CjJvnje$P-HBb+$RvjG54#y J?*?GV0|4={u7v;q delta 524 zcmeyQ_(^d?2P4OAx3D#mzl1kWp1|m1s=76=?azk)Z<#AwvPC9+>}6zNU^v0Yz`zcq zZGhMZh+}{_2Z%2KF$V_&gUV)Jrt|Es9*)5tB0wP!cog)zeu|h-7N36PW~<94`&=SC zede$+FeEXsGAsw03F0#WX#t?x7NEG3^MQMcJPZu;CZA>6v-u#`Ek?Pe0X)hKs(~D= zjzugD6^u-5N*CraD%dbHR7wE#Pu|HBRWBwuL&4)5OJal>$LY<9ku%aF*$x%TWH<}> z3YcXy85l@UNX?p-x}bsAacd)k3ik{J4hH3g=9Zg`c4}E{GT3Fba{KOuD><3I`v|n9 z9o~?8m@Vm|MxJwH>Vd1FiOHL@i#?UKixSFfHdtv!3TP(&$E^Qk*8o_tzx z@6w$Y&z7;sZhp!8i7`I1L%{WHha*#if`m`FlE)94mOtQKFVxt3{43RC0u4n z1t6gdZ9G>qoESnDIC9EN3Gk40<~3)Lmf$fLV3L?3@J6RufMu&dpu3fRP6Q0K}K8TmS$7 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_null_0.azshadervariant index 2f2cd5cccff43f5abd9e32854ad3bbe7a994c792..6d7a604701b9a849b2be3939000072f11beb9371 100644 GIT binary patch delta 16 YcmaFH{ET_SJw}eXU*&x_FfcFx06q!^7ytkO delta 16 ScmaFH{ET_SJw^@&C;$L0bOUMt diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_vulkan_0.azshadervariant index 8fb8e921175bc2cdebc030a8b9d3afa075d2a469..dee941cfae644d19cb161c0826cae0801f7b7d54 100644 GIT binary patch delta 16 YcmZ1{xK41xG7gTpU*&x_FfcFx05;$SlK=n! delta 16 ScmZ1{xK41xG7b&~C;$K^N&@8o diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification.azshader index b9552a85db240ae4b45afcd4f9492ac8421de7fd..e2e0fa90f5cb67db90fc3022210ada280ffb5e2f 100644 GIT binary patch delta 4323 zcmeH~ZA@Eb6vy*uJ4>L07LdDA)*=ja*!x^c)ohJ|8`(+}=md=>bEDlBGhJ*qkzkCK zL?oz7DE-e~JKvf)-$Q#%&2Y|aRmZ{-4WOAHT}|}UHcE5^GED1pdy91mZr{vI`t9VN z^PKmb{BAU&o;<6Ps#WT@=S>zGt5X#d-E*xQsq=v6$vwMzpP`+0R>!TwJSqSr_a;`ANF zkkRf7t_9u5!LM~AUbF$>7kiQL)xaDvz})HpowEldH-wHVm>fG=jx(x?gIV72E zK2?Vk16*Lxjdy?F1XHOS$@|(6Ep>~MhSVY6%;Ch#1|$j{m_DsX`0{%4D9GR_OU_m7 zV#)E?KBVZq^(F{q9NCRgtqcBPy;yQHDaYysj(G8z!-bt8GkzZ8zz@5btOZ?cz|^pu z=O849;>17POis(L#p!xtA(PD48VvMQLC`iJ{z@Y{mTZ~A6I^59ct8GpwGw8BpM5qE z0lyS(MZ&0ssqG5R*U)Urdc;#aeC?F!&O+*@a!)bhCh~7rRi_I$17i=O-?c9oVAQMBA zo!iqOM)v-06}}2Ku>L#o+9;I^EEi|hEb0Z&akGuwLlB;jlYR&SvyT^5Bi+S|z5+t! zX>?;YC1;^$11=Pu1?-{aFon0i9qA6rI@*CEKV=iIK{~{XQ#Y|>PR`$o^zA%^kP5R$ zteP|3ixr`%uHT@Wd0q3t!aHZa8+sxxj+BwL@LD7JP0erW4ZW$c$js*?cPZE5;Exu} z9jO?9tCg6E=F9J|nD_QrcEsM?r7gYYGRIPVHR_zB{K?Iq-2eRKn(*s;WBD!3gTW08 z2G=>awxut|9(%t;img89*6W_X4&{CrFDJ_p+fbZ3tiDvt%pFcCn>^ zl;DDo%Ob8JW01kzj2_adk}T>fZ*#b7L;Q~xhIDrZ1{IZpyo#(~uWYg}L%h!9KZ*D2 z1s9Tffl;q4EmN;-^EdU1`;BA;>}|^AmqTAA+ST}LK+okCc)A$bEpizYmOU#d%;H^* z!b-sk3ispumde0!#iz8?$WWNk@w}bEZFLrjwSguejdS{*?E delta 6045 zcmeI0YfPI}7{@sV91AOjF~-Zi>;hqfzAsyq>!1vR-MFknW-!Llb|XPC&~Y2A33QRn z&bbZy4`9q9og*L^ptZ#D!An07qtR4iVwM=)FwrkAZjCOONCuuhr34Z`xcI@iy#3Jp z&fD{zTl1Xf{LbfJgw9NdInzSJlpk7ZBHihsN|th=yg<~qwZ7bVs-sX>6+p%KKVtM#6&WMJ-eTa${ zP^>XQYCD2^ttQ;7OvjbC1pAW49;=2vX%9x)1vsc^&zImm!|PfULrS(4HE#E-Q0TXI7g6_j_X?o)y?AT#^w3MMaqEGGX<423ooW zsEhnV?PPPjemumU9+bo-!1`MPq~da@&L!e%aW}M%L=>LuW(QH~n4}unT{^eNvV{#V zL@<#LxfUO|5`Q3~H=Ro-?G4I>c0x$4|KSdJ1;zo0bDt4qQ2K4HQ5Bi@g0?cnmf6{<|ZUG;&Ag(rT!O>sV4Rp$2ADq{Y5u)AHCc8AFs zTF%gNhUTY`|0+X&B?qj0q?V7=5_=3Y^VVDL&*GAY>ykrmz8J#_qutK=be3X!6pg;| z@!ho?jp}A6q!l$BlgSWss)&P9z4&ENs?)rFsn*c1L9teOH;eVaH$kyxOCwyWuP@!; zG97p)Ak+a~muk}nqc#O}dad>*r4BsXpw<3iZPsco#e51@n+o@11+Lg>UL!AURP3Aw z!Tli6+(ymz4_xYx#lvo4UANa-va%>f^R0Uoxn(xHK!7_-+r_v;^hOK_V9o&AiO1Ns#_| z^k7jCsSd#^AM(yUs|}O59?F*5#`hz|%5HE=7FKn!R)c~`FP@v;Jm*;4k%vdywm zCwifGawTe{2}EOHW!ok-bMzx5GNN#;NWCgn7ucJoF-CViL7j#o=wwz~<0A;NW~~io z{L{lbnn(cbpC0_%QWb>!ydYPW4UbC`TvO9`VEBob$HC?qApGZh)O0$k`l%XVhg^{{ ziC-}AZ!Z9^C-4YsI;e_+k2l&y7)}4 z+(k0E3ReM>t8~>extT5plbhx8u(T|}PDU=>1}s-Wps*j0rZ&I_U6 zR6$rfOlVPqNeI}Ef=KoBELyUD)eu$W4+PEz7E5kMoey-BwiT7eILrK{iwGP_tJx87 z4_(YogRcEwG#YD<`9SRdOjc1nVa9DD2p*&jXj{ul-+AJ@RXQFsKc{lq?wbg zrth%h7)t>f!z2tv1D%YeHO3x3RIjbCIiwfabHhBI5atPfkae-SEP62l(6--PM2t&H zoU_58-e56KaGw7rzqdDu_p41Qze_xLI_=uQUY$u*FS4(Md7ucNXPLS2p|rRm{+ven zUGbNij0`m~9;%7uQY2UFKzo-~ZckpZEv(-41*Wc?y1&$TJ8&g%SBg!Jcz5Q(yxkI> z_?g-}ULI%$6_WX>_&x~z6CYi(HPf9ja8VY& z)lFU;B1Z-;#*PeRTvUt@ zSa@Es2l~<0*(>s#8IywlxuHU=!bC?&9@D>b_kDIo@?{DAhFBPt9FIyCUE)szz zsy2se7-1AYOuIyygD|h<)uo>~R@aptB1(?S>*xxp6D0#MJpfyUd3QlPF}2!?iW>ca zaOCg7AhsF2+dvB-X^nP!%Iv+ADwE0sYBa+p=T4Bd%8Iu2E8dtN)QJvXQcrfW$Cu*I zPP^~hY|Ghtf%){fIqR>?XTF|5mc8cCT$9l_pq~CwJ5gSLzrZcQzbU>IK#UIN+8TX5=whEFyTtnNlLwKSDN7&kpRb+%Ccn?VeP6ri zRscPb@P3PjdG1Y4tBuo!SD9QKvd1@7bz}96rg&A8k$`>RSa$nC_jO-(=W}e;(uz0J z8nn8G%EP~AbgdEo{;K#zd~aLXXQI8rn`eon9P5{{CCZ1z8#9WP843PP&CBk&FT75c z+kJWd_&mUv%@;f}#(xDs&${PlzEEH8cF)h|bBf*z0a*T*-VyC<12f1V9n|w)Wh4bf z=o*;bK~YKvlk)#XX$b5;5v5J^GNS|5(Qh*ecy#dduoO7y4D*(DA)?T?a%6qt$JeuE zxjS|;TF0>P6VK;rf;u5Y5y4e$F8|+jia@;Hu)l?IW>PctX&>>WVgXTnrdh`lbP@?~ z0BLxiPGs5X`vQ6+w-eVudGAGV9WEkK1QWv$%oHS^hh1-=hL4|2(?W>8j&7yztbO_= zMEj-^yE>#5UZ@hHzSqUCn)xq;TekE_G3F4wx36k1%JcIpM3`s6z%fBONXgrE;~+L3 zI^lU+(e7IaSl^doIx?Sct)3v!seWVWq=ztvvZ7E=G5uC|E$xA;mT5 z?7kVNUL{1&s%7g61Zcz_tz!@JMIpmthwOs!@c`XGYFvY>S*GCMh&Yr3nJAahoAcJY zTgn{}fuS$rD%M~2{d{mzZK+?cET@78mgwBuHY02xaQ|+omr_V@4Q~yEcs&>^9lJt}N=BLKt(ANS)k5Jts@RDzi}931zM{r^ z@K|$+|>&>*8!8>oE@YC28!w*$LTWo)Jgo@ln*>N$1nY?DMu9i25 zOsQB5LAIwqTA693S|DMMN+(gBHl9+`8=^LDzeEBhWp{C4QY=Fz zOLn*hc_-J}@k{`xz7TSumVJOidx(&W;PtQvk*hW%6Qr6urs5u{MXLe>_i)}st delta 2467 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 RpG#j_N%qfQEnUIn{tcn&xE}xj literal 4898 zcmbuDYj9NM8OKiufkZGs1w)XM1?wduAwmEzwYkCuO~@u2kU&g0Y)+Duy@cIO$THfN z)((-e!tkLCYFlVKrGg!>by{&4dvS(I#g0>ZF=eJ-Xg<_VwazfsLTl~+clNx=X(pY1 z=<7WDzR&-;ywB}DII%3t${)#VeQj*f`mx&LBOjE#@X1j3tE0a;`pCMxv(-GB}FNj>da_;#3 zg}2uZUu{}3ug~f%-|+jZ(-bpb87+BzwD@O#SbQ+?L3_>D7H2CzKlJ0^ey;xh#~pk2 z?%P^=tnEVW;qmgw{B!v;Zk=sec`9eIwcji10&9kg%&}&judh8iJd*C1Zner@=`_ zf}yR#$PgJTnTqyB6JR-g>X8_XE3b6ONrlMKy$gM6=Vr|f;Q>1mP4o$xkW*(@-fR!c zK|_>eR2$=)9!%KRCkGRmv}8qYEY#eU8LN%M1IdJwP^uI5)Zf)<%%(F=%1K8j?Ww&h ztM9iHeNKD7#Qn)wk6_u~;NC$WT%9^4-JeM~>GTx6Ij$c4aP>B)Qg%<295yB*$sVN} zwBvC*=X0*BOI>ohi6JMIcK(}*iD8b>-!d4V)NOZ$ofzXVQIEMkJyQ~+HOtM&vTl@4 zBAJTYvAU=&Yl9aHABsBrawvGA8|ysdbDN!t+Ph;;$nN0*nb`Q0xw)u$ZAndNG?~zJ zC(^yT#MR6B;r$G`Gu50Na^h-IyI#xWJ^F~{{DdQ^WGvRw+naXOYTc9T^-V@zXGiw* z>h<`#U}9Nlbef}yO{ruegPtjbWM+mJp=bBd8(~;m*3FaHJvwUIi!ACs&3nqdG*@Tl ze|$57`eHE8*ew;oGr#bk_IT!Tg@}b5e!0u#c;?M7heysELmyv$IXrUS8FFR-pY)~C z_hxSu&oUVPz|c1sKEV98t%39QD4kv~|24AT%=!e4~UqJl^#z{EW?u%`i3VTzdpHe7jk@)hgOZ@$>G`K=c^4*{D&`Xi5Y(- z;sYWhU#v6B$V+wR4&q&+Js@Hshrh+;CVA$T_)1j;dP7X`#Ap_0uz-Bm2pfpSJ&(&5_1YjpUaJhK58q2-<&E+#xig^sJ`u83 z#YesF7h%gX*aJF);oo3e zHj8RR$mrig+F92XFS3V4VDymlHSP2m9{iA3hbEnCMAYV>hc)}KkTCkYMT9OgdcIP7 ziwK;aGwUId$;sry?6-QdXXFdM&BOTq8Z7MLe1q{vKiWmcpTE9aJ=t9Kjoxe%F&E4~ zGQQK~`-pb(W&hCA-L5lzr3M|M9U^2mYTqg1n~$thWMtg&sL0rLd9s(3554I2iyA|B4BuDf-{ca6x@HKH>(^H89@N5pqww|Rl>uQ z;>jT?A|AsJ=u96+yqfNHW%_?|?aU?L?3BpNWvR~e314YXW@?`ik3IM)uOEXt69Y2( zF{GVEKalMcfl+JD_@1qOSX3yA$Pech(JdmD|7~MyY_d8V8_w7)6|wv_RpLKZC-0@3 z+o$_GhQ2c|myI3_9r)_Wimp)QxyPLS?_DYQqzm2r(`TwXgFAY^apAYun|~Poh4)tq p*UwZLH&6dZ9xIz%ckRxBv2T6p)+ubt%d*q diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing.azshader index 66895758deb7e247b3d554cba2bc979a4ce886da..2c403c77f88b4e7213022796f694f866ba71160a 100644 GIT binary patch delta 4723 zcmeH~Z%k8H6u@^cWh+r)sW=|(kiX)D(TBhU3W7xgbP{=;UsxtsI>>Zkp>b>z|FzEj z`7#OVksbksE`*7bj>5}QQD!QW#C_4~<}_On{ID%q7G=p266411>mTSyB>O-@vh>q? z=l(tC+;h+UovB}QvCCeh6Z5GQ3FbcB6am z-((X7PlQaIGLFPNdtJA!u8=^9O~9k0q!GN1&7z>%FNg2P;;?Fh#KVna=V531erUfF zBPP%8UKN-kme}4UpeT!`2by6xArXJSOjO{ymjc#=bTsDDE#OU1fhVUD1uIF0rc)eT z>}atWR-r48a!_qop*fPA0RFTIlk_wJ^6eb_c-mxtlW5^krwL{T(lIHY4duE_FkO*> z%>_*OqRWKS`-mR2-O>;xPFqPVt|_D(T8pR(tc4$v8i-NX!{GrAOSP0Edwe2O6`I5- zyvdrtSge9=MHbS4$BSq#m|HYxUQJ4g8S0BWp}fZg=CcLxYmd(Wunwhxria5h9oxXz z^9i};TT$y=2X(z1xz40`Xzy)>GmeAkH4`=PpB=R6)Yz<}dD7y{Pa4*#g6v6^B#Vx+ z0SZT*JX=}`4?C4G)UQEBE8)Sx)Qtap46Op?VW#{lTB_O4bVUs+;#l|LfpQdfQyIp# z5({|l%Rm^&l>E07JaIBuZ;t>;1O+z!tV^3Z0B6+O;W0)mT2M+=ET?=Ct7d-{3lJgZ?QiK*vz ze;G`&R;Gi}W+;Sgk%uG0ZhWL?dYjKiV|y`Oi~OrpW9OIwQzHiZIQ#mKBOj*?R0g-l za^%M1lCH;vZ8SEACh_0rv3-|-_GCbc*cFpMC%mp+kGTw2|%A(yYMgwZpP(v zJ|1^79?v8JaH*k;v}Eo_FVb20!e|#}Z=o8A#iAkOO9d1{m9Hg;d_ho0Zz-*ur*w4X z(&LQI^X6wWk_+K<)?LZKEfpLc9OLzcVL@p3wd`Zm?(Ygk_drVszvrQ%fWFW8eSYv_ zh)36bB4ug`jWb9MlJ7_;&im!XJnx@$raRvc^$s7)=lZP=U}z>I`@p6Fyq7Hh_nY8b zMq+3sT{TyO4K>zIl>Q6y$2~B5k|C-;$jLX-7 z&=)wIBg4^fx39|W-A-987A_0Kkh0+C#1FDwKe;typ)82(?Ed!2t()hhvS9q_ugFs_ zkyO-Ay@*0Z_=X5IDC`-mj(6`H%WTK++WqwB`XsBpHmZe4Gmq=8`h@y2Vqz- A9{>OV delta 7886 zcmeI1drZ?;6vsV3iz{MzW6DFVGUg^qi;xM*peVX3K8m^wAGCt7MYBLKk+=HNe5~~NYL5WtZS%Sy}o+&it75czW96MNCSxUJ>m&z=o#hF}5iUeNCGo12>zi$-Wpypl_QVdsn8RJaG&8 z+8`h0j2y+2NTbY1kuBXc?j0TXZ5g5tE@4bm-cd4KAKnGz~bXSr6^#e7{oG{D=2`G2jn2QEn z8t5hF_qg$zM8-v6ROXparo~{yZq(7IL!>kGafN7!wV?f8C+U`oPU4-6BdZ5;uxp(L zm(9pl);)t>m?wPJ`LGZTvyA+X@%V>@bf5`_lKdHDpsqeQTM#8H)_`YH3s=6xNing5l%Mcl!6SEnV3%j`&NlSh@#C4tKfL?dp3n9I z<^tv-<|1Y@vzfV!xs2JuY+;_wJe%3dY-L`^ypVYr^D<@^vx~W%xt-a~>}Kv{?qoj6 ze3IG6>|^d??qZgiWoAFKU$9<+LE!l{8-_?Ju&T->x>FC@XhsF2vix?s@MUmOgY`YD9L+5RdM20KQy zLS+F$J1Yt6g(TmHSHKmBC?XWn^#`zD=!3xrghfI!9TIQgA(b$V7pq8bxgotUVj7Oc zyV8T|VLxkFM-0xP=ym}`@km%r47|f`T*TlNI^SqjTvWwH76k{mxR~_S#rvD0e#?r8 zi%Az!pWSq|yG;=nN71x%@X>%xog`A{VQ;n!6;G-8GpFBOi<&>x%NcP&sa#X4moxwA i<;8L}%vM^y}qUJU5Tp;^~KRlIahdU@YYT diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_dx12_0.azshadervariant index fd22ac4fd3160ef56189ffeb6eb179581c9ea614..4bcc47ee43a6bcc8c2b33f451d22a0b963981210 100644 GIT binary patch delta 17360 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 ?nUKhhg}(PAJj}?8$vHeJXR%dDDZ@FpQgQdz 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 M6I&Dt4H)qM06r6)`v3p{ delta 16663 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≈Jy|H2Ywd3wc(v}3V9(os0Ow9@ z6rGCe$*ZPHimOc^x@z~t($25JD0=ltK=J*MD9)YOyGEWzSFKrWZ_xwty(+HOPK{rH zmRxyU2I}g|X|55n@CvHQq5vy7W57iAd~O>$ig=v+C?A{aGjM0?aWu7CF=2Z?1`Dih zneZ@PYg41cWW`%UkKz$hQ@|uU-5K0Wj)R~^SD_V~26Cl=@$t~oBZ^X;pYWRvu>~IRE@K{d^ z4!9cdq)US)cLQd*HTb>T$!u)jH5sC__Y#NiofATVK9AoG2{_TKqTo~9=j2G^V#s(5 zaxi{y60eR3cxSK@uMY_1SHsf~kGWc&<@`d6Ee2m2%3-IMiJikd8nr?=k5tU^@OWWd zpr&L_Y4T^3e31KEe_)k>(RKo40T=s z+gnn^Z_i}|&Nj!P*{sKhM*R3%zYx0B4Y*~LozjgsG`_8uZ=w`$_6zKiGjY=xPtJIb zP43mBzf48N6`Timc?5Q@I{aXq$H1U~GvgJc({S_AP_U4T#iJsxSoZ+?;O~=aG8!OV zY1vWKd8;eiOce%bRo?yO?z>f*&$eJs)sM?5W%TNYeZf6Yu{v7M(RyBa^-Pv3ZXaGf zT8gJmCX266XdaAoTRnOw4dU$NW1zgb+aY$0SZyNzr7dYW^&f5J(N?~4TX`0(<>A6| z>N(oaqkOWG`Q$$Pc|%HtiVsYW`i>x+PW;aYu!+Ojb&B)EjU`6@7S2;~D#!bb$(&8; zW4K-#M)gXLrmI2WyFCSeDkBbNc3>9rUjd$>ql%`ta_=v2U>M=sO1OIwe%ri5nB(in z@*JbofSFs3s#dj3^BK~vGvnFlVMbHC14rsYv)Q{qDasfRyfn5Rk%Hqy$(P zk`l<1&W?fidi<+L!!&@rA+zK%br2b?mvw@iDBsI32nH#fiQX5by%^QkNG5-oWMWXB zh_=36m~dP{wqId5sxFqHE`HO#V|e+)CpJs!LebIn&FzbUL8dOUsOfL$`~NR8B%m+* wcr6!E9MNYPeU?$te_x`1>1XL!;Rys%7>)1%!P3$13VQXKv6&*0(bq*{H>oy*x;$XgIg_!rX_dcz#p=2hOY2@*8H3}X z2rS{&{}Se2^c+)6RcLI1Dj3eHO-}x| zO|*bWEE4As=MbBT&BXb{Hex5Sli0<&8_%)e*rlV_S5A_Y6^+a4Us%~BHI^=^9~39@ zI3JIFegTRp*ccD?Di5qb&fllbfuu(nQxS0SIZx$4xD*%&to znXS{n%p$M(m>3?5+to(nPb=}#Jji5y8_XISX99~1;eB8(dm4Mt)0)OhS=Q; zPhq?rtjzYahuJPq!@$S9k@(80o@S?ejhLJPg%DC>=1m)JdZk!1(Gh@(-wpkn!o7b?LSM#tN1d4&#rjCMAEC#`f zMO6?~d#VA%QdQ6;;960T(hE`!fQ-#1L1HqVWPxoGUyl*v!-RwAJq8j=*VF}1ccAD1 z9Sijpsw+3+jcRaU@Bm2sJIcm}c~F5~fp_QsfJboJ!-4~o>gdoRSb*oV`NeFR!VwHC z-~)JMLg^w_Tp+Qe?&OpCRam4HSJ1PJ>ebLwbtgJY87P9|w!UHE#JYC(4XHxH%463}d!-><^xD=+N;6jAox!AAJB* zU9`K=ZqV|amglrQr{%eSn&*m>P#Yc5?jL%)2pWgy>%g8%zfQqTsl5UFeABLE``Inm zzYN3_i%{`}fMh@|&-m+OXiI zT^PColbO6rKgbed@;C6PMrsTuWbWu(>U>SO&<#aUmY$m%vI;H_(^C#Mh%Qumpn=;% z7p8h(85f6t^y;^VF0}Q+Le(7l23bQ|fXqg`V<&Zpi5n1r5LWlWHVEVLoqS3Cp3pbY z5mLB=C7~5lolr~u&sI#0N?bb&^0+eOQFTIPzc*Ynz!y?nlQAg>1>_j{^*vk=8e{&U z!uy&&)bt@&iT?wAIP&XnZZzw!jZ5ppktZxqG@tEmQ}yBTJJ*W;X$p+-6xcKDUfrRV z{^&J{mj1N2C%nAW-k#jy?a5uzpIS!7-pCdHqE_t6kh4zCne=V+*N(*^UK}qte+Pqv BYDEA5 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_dx12_0.azshadervariant index acfb2aa716cefa73d2c05ae61b45992c4d7851ab..93cfb4781977a009b6b4aa6ca9c5baacdcf9a5e4 100644 GIT binary patch delta 4594 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 V4tXx<{~f!Y+Iial!@H!({{fBa&=3Fs delta 4715 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 Lev6E2o4)=F8)W`M diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_null_0.azshadervariant index 0bf9ac53d74137223f9945e8c6d37f613db3440e..4a16e24211faaa39226db82f9bd88979700313f2 100644 GIT binary patch delta 16 YcmaFH{ET_SJw}do(5{8&F)%Oy05S{(Q2+n{ delta 16 ScmbQEHAicMh$sgG6aWArCIW5% diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss.azshader index fad06893e96dbaaf81d581f58b9d3081c49ff33a..d95fd5b3b2bccd1f9153241ab9ac8bfa7dad6a3b 100644 GIT binary patch delta 4533 zcmeH~ZA?>V6vsV}6{<^TdD*y>1?o%Zg3{Xt2AfK`Z0KM!QgLs|cu0liep4RQDP$5OcZCfFMeT5_Jv5?bKBcci8J97S<+9v z=XuUO_nfEybMkxc{<-qR4egLgv%=ri+L#*1)?`3ZeaU9g-q^6OZclTQ*pORW7wD=^ zNKLp_ELFbV%H~^&SQo)U8k*Y@z7_ zmWMOld+^o?C(R_lW<2O|lJ9-6;WNEXl0JZ!Xl@@kDWrumw0WH;m#rfu7$&N6n%_7UmFGWkU`TDFC{3| z;8?$#uNuga&rij7+DgG~Y}KU{@G=S=0Fh_Co*dhlxhI_)`ZMD=HN=0tI#HB(;M{IqtP&IRIv~tk#fGh6Fk_0w%QiUq-`# z7#Q*w07`a|+^Jjz8wLl_@fFX_2<2$pFOtR1UMEWnuYqSoK|8adakq#a7i8T2jTk-N zVjMrqBUG?m=>A(I{ccvWeD$(rI8vFbb!@fu&U)9`>BC>ZO72dm)jqiM;IpcX?>AB9 z9Au(g^}}Lyi=C#cflu0ZCC0TI*Y472H{icKv0R;%_~}RmrQ|@GTz(9UpuKnVVA<#F zpQ*reKi4NOR@?EJ9G}TcJd?91(G0_j6>fYem&So&X@TN#L;3X3ky~@V$x*o#;b_t$ z#cgL7kFZNgQ3B?;T)tAlWUlOVYR_a}Q}P(>oo9~VSPU=!HTh^>Hc;p~r>|IO_T79K zn)4zqDq-m{v0I2Bbl5S9&`uQ!^|+-+;3yq=E6UT{%4hYQr}M~Fz+6=I+dNN)_aq7# zAr;^A2r5~tiG}f+AfLtXb;O(pY}Iw1vUy_jl&$VAKy9_CC~qsJENqX+iwfE%#^)A$}WZ<~EejsUnuakvmVZY7`J}L!m!|gSh%71+HDm{3fDe`C5{$!?T>dbv-Gt zLk|89<#9HDn9cvlI+XKHXJK{>o3HSA$L~*0oK@KT>Y}?u=3O!yL*?-f3ExBG9rAy@ ly*{Qx(0{o`9@nr%fEVo&ny4{ delta 7835 zcmeI1Z%k8H6u>>tGVl-5f{+#vh>q!0`ihVR975eH*1@2i%wVPzI&pC^QWcE*BF#w5 z{K6_{a?D&tQL;a>Nll$~OEz)Y;@sj^v$#291h+&t|ABFus8e^}d8MLpMq`%n;qig| z?(Kb-bKkq1p8I=Se~J6!^q4@lE+%2`%2CO|>AEx^?-?+}yVf>&>esBRTeG5WRU>Ua z15-m2n&4?E7_QoDh_TPL))Znxiz9eq`R%wE`vTAIWoXb>qxVo5`dwu(9#0u8;&-mW z1bSvY^F-!}%tmG-b2@VtvxV8hoR3GkQiHdS&wz}Lw%M{{O~dQ;uQslg8}gRb-xXp= zgjg+MxXKjzau)n9Vp2j3HncPW2Ffzfn`>;#O(pMTNJY;iGg{6TLOSkFucNHJkVpf? zFopW(fSasK6xt3(>b(N_%2;K@Br;pU*mf?JYOV05=s$A40}62Ug&ovW0&cWEvjFvP zxv76KJVozc2P1~hyJ?^To+RssqUE{ZM%SPP2RFH?cL}6W%|D`d|3x?XzJg5jUoxU= z;7)iHh>;ShxD;|Q^HM5SwtB(O!3K6h0dygptHXiIMfg*zTNyePeLf>~%ol456g9y< zG1NriPa;coTus5A&1p2pE;<~4+0k(|xBUfJPYy{+!=-KOA&;DrRKfSfT4GiQR<_!M z;gXLeyy=&fg}j8fI%V=y!XXMcLB=fG0lFP4KtHba7rC_P0z7C5(nC(Ecpws1INUHg7Rtg};YZ#Yr+bVxW?I zgD{pVsv%nmtco_oiVu`$jwRa*ssA+S&|!X}-5_O?`9+8)IZ@gP30PNZCULXlDf|k| zMb9=_*%(gr{U$5V&o*wtDCH-*@&9wfs~bC=H*?moO+J%(=6yE2@{g0x{RKRxfVqgd zh}p_)WwtTfnC;AV=5pq8W(Tu_xr(`pxt6(>+0X1}?qcp@4loCp_b~5a-p9O;xtF<@ zIm{ep?q}|29%LRAY?NSB^n#%V^*4h_{XlH3cXZgeAw?38=9EE3>opzjIV75KN)rH& zxWv%$A~WR0N@S9svT5??a>aZk8n_ZjJmG3=Vxcb!Hdq|*>0CU)U_67J<#0sB}FSo2cB47PnEw4 zozn1HeMms;|E};vdNk3-KKPi@5LP_I(RbmvXuJW^?*g`P@#HIlCEUD6>e*GHM+dGz zyW;Wk)obpOd5vTqD~*eaJbyRXg;<&`#)_-zRBe^DX(kkKTX?PMG~qen0fpdGr;Av= z$lSwKU!-fe?~7cbO25eG!_8l$>t6k5kBYJ(^_QwHWk^OP(S=elf?o|fdVJ1P?}{n~ zBXi$n21!{jSrQsR zACS;zi$mc66oTdqHD?GT))^*!|HIAZm}}XpGfX;Yn$~>uWT)Z`Gim+-*zus^as;H& zkVvD~AI2VPDO5|L(Qgy&wF}!t?X?Ri?`a?qQyo`}9EXylnv*gm(w}}{zrLQks>QJ6!Q{G~pdJDMG|vM7 zhrVI-CqjSe7_{B)hY7$05BLF)4e;P+R{)YSQ_`{Md^$R%3mun8t%H0r054pTgusyY zPjHtZ=n0aB=Rv)Q8vkrXiMF^tW=S3V`d!z(XWA9ydyHCeJj%`jnCxB_8E>!wz#_9~ zqHI{3behr}_L=eK2IyopfC|XPTQN#iz>|$@Or>)QFo#pJKCg5SPLkshO$bk;cUvX{ zOKXp#LyKK3*P#k(Jt%`&Rj6s^G)5$=r%nY}y?OgUSSRS^)3&|viPG4)l1ZuA#|z_P zc3%tls0YAlff8mZ!TLbIIKt|*DCU17V4i>o0?2HxL8Hw zzaEfzMx@MpeZ4Rs3l$N!VvN8Tzv<$%+fKsGr@}8Y_uNb_@@1f#D+r!EoOzXx1h|~* zp<@)It19RYQLDfRpu_w5xKKqQ&v73y5k1`l{f%y0=P1J%PwMG57L1P`M=lU08bd-| zXI!r|{)%Ct5xdYLi9dpk?=|?D!3Udo8H}Lx--yaW96_FK!Q7*(bEYHh38b2MdG!9u zt?89YGRtsiO3Ci$vqx0i0j1ZdnEPDC9&O|fH?q6M%;z@t?MC*nj+Vn`PwKpe`Rp5f z&cF~mPsQ%Bae7oYY=}MI?{V&K_!eS9jde%#wuu^}7NfQ&)msaAlV(O@f zwo8i{tkKP+NQCwrgU7435tF2rnx8(W_N519u{{JV>P6L-~zSx4jp{mI>U~_;-G{@jsS)mMg@(+57GnghjY601*gpn4K)T7x%{ilU` z(nNi#rM`5yhJvF$2*ZuZa7}PONB>=wc3%B6r>aFVKHH(J!yOzmaK7eGmE4K&D$srD!hqrZ{K|Xs_N3m+D(||k;+;C6Re~7b4<8F7Z zOSq_u9Kg)2!zT7h7j;V)bVFei;zbub6Pi00T$C;_VOh*9`0$_Mrq#Vxx&*^- zeEd2grtztKMUorx6(%!Tj`2scO1Td(0rEGBSCrfV(av_X{BPI*63zCkrq8Kbz?<#yNGM(>AaBu@Yt*74JhNEDcV%uD z=}62=B8bX-ED}?hqgJwr@6HSqudQ1?&$ag~fFMRCj1`spfcV=$k%iYXqe0*y$b6Fw zmgRv_0akR;2lU(lrXsxd{b}it*ZtXpnRSGCwARpp8Ht zx&SM>G5KBkB>)pT-eKOD1oo|gx1)hN1^67OML>1eO; z%!k}gI7l8woM#Ij>BV@qlfA!$u$YKxq=U7_)wmk$cGEW_-ad0R{v}(=RAmKQihQe# ziIu^Wa7l5=maN?5l7gHS#j5OrqK&>)U5S-KxnZxzk%5NHwJTUhS7vgTJ!HRI|0wf& ze1MH6@$NG}#)kYHy!!pXgEHaE)lX%y7i{vEhVA7s#hJF7SNH5^9J_O`yrX)*=aB7c z$Nr9cg|Pc?yeU2Ht4HOy1KdG`=yo9{;MaIc=dDJ+$`tB)p(LQ3vX*G4cx>{|hsUpnd7AR^A$WD)l zv|5A|kVY!?jfg1m-5HQpx^N+J^JY>54{WvAH1bpdp?f_aF7YL z?=%0dz0Eo)$!Xv1FHTp77Ve9>U3jwUOY)hj!XiDmZNmo?FzieEtc@v;r-Hxpx)EIG zC5#n=QKg~AN?-&OC>X725tltuNe!r(+blMDp3#h2$(jk~+VY#n%J;PH7nj%A(&=Df zzcNrL89<)S3Dhj?*9I>V!|lh0XMH#XS+{9(`G!Lgo)Jp-dHla8KX0^q9QS}y;? zKngo`#^n{+C0o?$xAXE!bIVFSa6Foj%j!- za*Br}qtEP*@s`OBjJ)p^Ee5}!{#xAb1s5m^y9WajN175}1T3CvTKtbu zB-tih^7i56uIBXKoQ#1SJ)JZxa&rbYGG%F0RpeYWuIkjDP1u?)Hx*rvp0_3yY-mb1Xr8a14j6_v4bWU8Hl&dd3V#h&VH&kzM1DY=e(@KN#NKXY=B_zncRI}JC zmhE@5pCwK=+b3Iw?Kk=c?(XX!?6UVCAHI9-;WfwbU{}w+;l6HE;R!na8&P=VC#g|t zG^S&f;~9}vg{d#bPK-yK%!oX7yZZDO`>LZT3H#=rN=Jd}3h^iO3jBl+Z#C7De4SaJ zwbO%?-B7#m*G<31r!`1O0Xr`{(@TS^=b8J^>_xVa2R!4eEswB|9FwHubTY4 zFseFg{7#{vW{h~RS$xhW?>6KcVp{Uge$;sE-ZB&bHt@?(00=JJkY7-iR#23K-mdkP zYvfqX-qc6m4XoqtU*GS<7lwCMnn5RjC}r= zX&veGoJMwj!p&oUJ=TG4UB<79X^|`D&vdr&U+_>pNd+aj*|R|Rt`q3oS7xZTqj2*s zArXaD={@|jwy5#RC=U%T$Wut)BV+j*Gu{g(FeB7F_fKFUVZ&85%jF6AftE7jpiDbx za)`Okh9a%k_D1h6n|CjtGpOSHV)K(d_FJtF%K9wmFZPh`&mtc@j$Cb+|G+%oE=}lf zTGVY{G>BU|WqkWL+)7#b$_M6^tIJmvxvaVU<9bKXdn4uVjcIcAW=~%&rPK7*>o(QI z#~^y;> zceBC0P8@_zzm#yXjTd_%7QJz2V=r`s>8}P&q;UiZ2L-Y59SJQLVq!0Kgkiet(!J5K z)(i2mmjoRhVd7iu1l|j5n6toB)7}((kFfu<;9H4~|6cI*wJ!|(2LyeBL#`uAsK5EIDnUF;8 zl*7!&IEl8msp8hBmffZgi<Ko*$AOCBnYw6eJE+?_&)vx z_4rM#LP9TcEnGOm@ZLfKBT_XUxKsT=&BDis3~rd-Le_mi=~Ws`_{|m->#mkUNT*LY z9`Pc#SQ^0qfU$9o|NH7)q1f7N^&`CRL*x4uM|5l;;#lD9ousBG|9miV0ROXW&4|oZ zP~jE)b$<9M%Dz(?a?WUOey)o#H8eC|YI60!B>)2j%N@0G)vOm<+LW@h*YzWdt1mv$ zVOYfDPfgu8uL3TK=m%FCYP56Jbg%g>_8WQMjnv9kkH}(!2w$3pI{NqDymRboM}}Kv zaL)Fq_f=|?;jF+kQGJfyVy|PZJ+%H?-?cuE>Ud$&1r<;I*9d=J9TK}*7#kF7NJZzD z?I_L_7ZuHN#L^WQVT-il>GBa-$U)bC9YB@DF3}p|+jm5I;Gk_tHM~gEBHnJUI#fwA z$y8ldAfl589hCF4&4)bdMb!qwLA)APi*WbA*ydOFMU)CkrNc+dFkpcg&NReN5azQo z2*#lbGsUVrpd;u%qGUVpn?(>@;fsj_hP8MdK}IG6oXz^HVP5xa6YC=AcQ!TXFsWQH zIy>xJE^y2?16-mfW}6Y^(ZKK#7`IK|eKw^HBeHigB?Y*_RIakdm(nKL^@=&&=9Id8VddLs`vvDdYgw+JR@_^P_%tLRD^X7Y%AgpLc;HY74 wr~5100e_-IM=zh->4R&uEFT!y#od5s; delta 4967 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 delta 16 ScmaFH{ET_SJw^@&C;$L0bOUMt diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_vulkan_0.azshadervariant index cf8bbbd82494b697e9f0edb4559340b081dc6260..34761ccf98ae556858256ecf25608fd87d6c67ed 100644 GIT binary patch delta 1132 zcmZ9L&ubGw6vt=MO|qM&ZMG&&e`#vB?Y6d}p$CNuR#DP}Qfqq<>cQA-C6Hu88WY4r z4n25Om}9`Bo`k{*J$TTA2M>bY#jD=*4^Xl1J3Fz118?WO&%BxU_B*>D^S|>4&$;>5 z|Fn5{d1FYt;069H_`$zLb1^o|7>kfK{ARIP_G{#_7&9gB6JO#vZirv>jEV_!g2%)K z)8TQkO};7G zQN_+{ET-5cjl~sP)tIT+HH}${t%a;33qw&9z7fJuO~r0$3~D29OJf6y-O(6yN8VkH zL36Ns8cVTG2um8Y$wy-SKZZ9fyq$??7X?B(T>SODpyc?4puBqu_f$ z#c*rb{6S+`#Xbiw2Mc`TFNKTDV3RaYlW`UI($F*3ar_J!ja9^0pC!W$eN9IgM4Tc% zC)QKTV=hG)ka3)T7)XcJdC^U+bQUPWPXsNpM9;{Xu|AqdDPE)*ts9aX@@qnU?CJG- zmVD$-QWo?;KG-R$2OY=B&?7i}>_;7%#dX^jx9!mk>L5pPnX@E1c95SViqkPxr~=*x z-C!V|rx`bgfp{U<8GanGPE&Z2Y+8IzKjDt>GlzU8a7X$%pB2klmxAqVnVYYkwi{^r E2qz1_gz9C|XDkitz_}v)v|(EY_qX@kj9x zQP6`24|5c(2k~lQg?jW4@YbVv_2@sKpzpgoYsZ1doA-J1e$3n1-_@_x-M3upHOo(5 zbnh&S54_ITgP;6Is->|UV=O_k)$49}^`76pvE{b>&Rs$*%_9Fu?7!kZzV2?X`u&01 zX?f(&gz?GPkN8X72c1Eme0u0hiL07DosLg5w)+FG=k@)A6B+SZv$-Y$&EdNErd7Bh zGWuygD$eN+9}{c3eeDp%ce=g%?&d|`?W41Fn0=i1L*IK8(Swc;$MtTxJ>T8f^qOva znOK?`VVo)UDR)-<(r0*195ZJ4gs2%d&xYPGNX>VDA++A=$3N@{)Z5 zE6LI03nBP3pkzhKz6AT@b?)L(R#=kZi=8C-qu2=L(zZyKNN@+7N9s8eS}U;OpC`fB z`JPWO3~-jXBkq}JcvLHL+@xw@ex}v0yKd u#@E4uy%>nxlZ1{TO_SKdD!k++u~XRNbHVN6DChH{WjSQLvV4v?gzGP7%6+8( diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation.azshader index b46a476221c29ba5256e057f090f56385e2ca546..c19020dc84df5e5bf3c02c1496d86967dce3966c 100644 GIT binary patch delta 4069 zcmeI#Urbw790&0HT+1NHl*ymlGD_S1Ng%AZWfvTC3zvUF0EHGFwi4-|tqYh*yIC3W zVXILS<6JEJZk)+df-fe5nXntjvKdfcbP35Wi4VM(u=wPI8Ht)W-H7MjUSM0)_+T`~ zKHYOqfA`#9&;8|>&-r1&{MK#Lbg9Xl`pNcAr{Xj{LHVyV?Gw9BL|=>?j=wBM_Z*3! z(_EEx)Ej9&KE%9EawsJ=S>~*->gB##Qf6k}ehk5~yzCRvcql#)9mMBfSg?H83fbC< z=>s)zzZpjGjatZ8<4An69UZb2YHlkQ{M(VL6HwU@X0b}DW^R!rB;Vpy&QwwM- z`Wyv_)eD%o9!8hF0`m>RsE0=e8&0yMHb|r+cOlRyKy9`n@p>zh_t6gAZxpB>?_VFG zV^}N>X?e0Ii5yrh)T0nAFN1nUpg0zrCn&*#EI9LQ0%~!X$&ZsAXIlhB=kTu59J zv9fI|ZhcyanA3%nUxeJT%*CIQjeizEV z6#3`$;;c`9nYPC{xKrVR-ERU(RoPcx{dUk28QYA@M=oUhdS00NejxY~mZXJDwPmX9 zpQ$#bJ#vkVuEj##yv{dC#k0%ZWT)%{se<8~Z6hA#I zZx|e8@@87|prnTyC^T+jTdEBiTGPL7@Gu>*Zp1L>ixa9WXif}2YD8nX4Jd{Yuz55z zYFO06H=r22_aGFRN2HMEE;k)x?^#+=L=Q<(xjMh+qlTqT=CWDgcahj9W#?F-$vE*Lv!!#~K_ttRPf$1O3EGLIP z{68x5f-pH&)sp*}u1w+7>e%27emq!`Z0xXuE@rBkA9^y?{GT~9{eCsKM*_2(e01oK YD0|I0xqN*1n}E_g@Jv2yJWB500Kv`p8UO$Q delta 6439 zcmeI0UrbY17{EEKm6}m#VS`J-(psk3QhG0=1Vs`GbgoXF1)1VPfL2(dn{oqaG%?aR z_a|-)%qO00N-ZpLO9rLvGH{zwmhixXb6wnGmJsN&Y%vNO#`z*_?A)(KaoK~u>|x%Q z_V?X$&OPUz+xzvqzqfx<-MXX>tx&0xhhJ)2Ev-}~6XOwQ5$|qp+TFObwS{lWZ)mJ* z*(WwO@AowC^6YJeufBP9*>k%q%bIpV{cW?9mAg!>c9lA6*Fwjg&%m8-gQmIdk|=H^ z^kNz@LVW=T5xW7x=`MJ2)(q_*a>NQ1b`Ol2Q{cD1EHL$_9mG?+Kzr3LkMGiv0w_LZ zfJm|n9BYb*6MMV+SHb*`9C2Zk<}(FPDtd%@kG0!?SEkl5{o$S*k%IKV+) zx0i}4B7ocP1yhceCaZ~=hT}dVM5>Q|S(^AwyuE z&zBc>QbUS?|Hw=I8d5_239M(QV;>o3Ju^T!d=S2k7@*{51Bh)-(3NFEiv`zw<0bKRJ2`0}JS6#_ zfx~?^NW9L|kdCaUXSD37yT1x*XLz=q8>vt3c42ZgOkB4?@N?Gq*7NY%wEUgMrvBO@ zfbYhB2oK^B7`5cVdjmY%<&_}J*uWU%+1+~_guwtcvU5udgM|d9rg?VRIkYyN*r5Fy z&u-%u@c%B)EN}P|w2os9!g_fLDfBW&)jmAUb3nau#wHvI*IQY(=&r3&;X;F>*1o z1KEM>M0O&(kX^`|kT)T_k=@8u$W_SI$koU-$Ti6I$o0q#$PLIMvWOf)4j~UA4OhITrs<^}ycJCv8jgL(i3^`oSx|m|DQm$}tDg3Y$+`V*VjI3>^ghE}pc2 zuiMH5ggiPbAed7?`C!NM-xCng_@0Eocu_<|8<)xm<}2l7!#VFVVKJ;E r3AB|;l2ELsY)v0!tNHIqVuUG;a}TLAuD%H=sZ%poMpk5#SM`4bhou81 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_dx12_0.azshadervariant index d0287e91ecaf4eaa8a647693c94380d9185a1296..a7d44b55413ad60e422335b85570eae7f8ef57ad 100644 GIT binary patch delta 4178 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 A0{{R3 delta 4113 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 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_null_0.azshadervariant index 2f2cd5cccff43f5abd9e32854ad3bbe7a994c792..82e00652163427427f0e363c96a18d7135e11918 100644 GIT binary patch delta 16 XcmaFH{ET_SJw}eXU*&rI85kG9 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�HG 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 MM)gm}z(M~10Ef;!_W%F@ delta 18919 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 N^pCYMZ;#Q){{zh%XG8!1 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_null_0.azshadervariant index 7922055a8251b89b19f98d9aedd460ebc6157b3a..5d8207dfdbe7d0e8951d889bb2ea9d98cee852ad 100644 GIT binary patch delta 16 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 literal 20213 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 From 60a0d2ba01d3e04d090ae2ce8add30b13df2cc36 Mon Sep 17 00:00:00 2001 From: mrieggeramzn <61609885+mrieggeramzn@users.noreply.github.com> Date: Thu, 30 Sep 2021 15:34:12 -0700 Subject: [PATCH 33/50] Atom/mriegger/decalnormalmaps (#4302) * Adding normal maps to decals initial commit Signed-off-by: mrieggeramzn * Adding checks for normal maps not present Signed-off-by: mrieggeramzn * Readding the proper switch statement Signed-off-by: mrieggeramzn * Addressing PR feedback, adding brackets Signed-off-by: mrieggeramzn * Adding comments Signed-off-by: mrieggeramzn * fixing compile issue Signed-off-by: mrieggeramzn --- .../ShaderLib/Atom/Features/PBR/Decals.azsli | 31 ++-- .../ShaderResourceGroups/Decals/ViewSrg.azsli | 18 ++- .../Code/Source/Decals/DecalTextureArray.cpp | 137 ++++++++++++------ .../Code/Source/Decals/DecalTextureArray.h | 37 +++-- .../DecalTextureArrayFeatureProcessor.cpp | 36 ++++- .../DecalTextureArrayFeatureProcessor.h | 3 +- .../Tests/Decals/DecalTextureArrayTests.cpp | 2 +- 7 files changed, 181 insertions(+), 83 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Decals.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Decals.azsli index 1bd8e0b9a5..5e7088617b 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Decals.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Decals.azsli @@ -16,6 +16,7 @@ #include #include #include +#include void ApplyDecal(uint currDecalIndex, inout Surface surface); @@ -47,9 +48,10 @@ void ApplyDecal(uint currDecalIndex, inout Surface surface) ViewSrg::Decal decal = ViewSrg::m_decals[currDecalIndex]; float3x3 decalRot = MatrixFromQuaternion(decal.m_quaternion); - + decalRot = transpose(decalRot); + float3 localPos = surface.position - decal.m_position; - localPos = mul(localPos, decalRot); + localPos = mul(decalRot, localPos); float3 decalUVW = localPos * rcp(decal.m_halfSize); if(decalUVW.x >= -1.0f && decalUVW.x <= 1.0f && @@ -63,30 +65,39 @@ void ApplyDecal(uint currDecalIndex, inout Surface surface) decalUVW.y *= -1; float3 decalUV = float3(decalUVW.xy * 0.5f + 0.5f, textureIndex); - + float3 decalSample; float4 baseMap = 0; + float2 normalMap = 0; switch(textureArrayIndex) { case 0: - baseMap = ViewSrg::m_decalTextureArray0.Sample(PassSrg::LinearSampler, decalUV); + baseMap = ViewSrg::m_decalTextureArrayDiffuse0.Sample(PassSrg::LinearSampler, decalUV); + normalMap = ViewSrg::m_decalTextureArrayNormalMaps0.Sample(PassSrg::LinearSampler, decalUV); break; case 1: - baseMap = ViewSrg::m_decalTextureArray1.Sample(PassSrg::LinearSampler, decalUV); + baseMap = ViewSrg::m_decalTextureArrayDiffuse1.Sample(PassSrg::LinearSampler, decalUV); + normalMap = ViewSrg::m_decalTextureArrayNormalMaps1.Sample(PassSrg::LinearSampler, decalUV); break; case 2: - baseMap = ViewSrg::m_decalTextureArray2.Sample(PassSrg::LinearSampler, decalUV); + baseMap = ViewSrg::m_decalTextureArrayDiffuse2.Sample(PassSrg::LinearSampler, decalUV); + normalMap = ViewSrg::m_decalTextureArrayNormalMaps2.Sample(PassSrg::LinearSampler, decalUV); break; case 3: - baseMap = ViewSrg::m_decalTextureArray3.Sample(PassSrg::LinearSampler, decalUV); + baseMap = ViewSrg::m_decalTextureArrayDiffuse3.Sample(PassSrg::LinearSampler, decalUV); + normalMap = ViewSrg::m_decalTextureArrayNormalMaps3.Sample(PassSrg::LinearSampler, decalUV); break; case 4: - baseMap = ViewSrg::m_decalTextureArray4.Sample(PassSrg::LinearSampler, decalUV); - break; + baseMap = ViewSrg::m_decalTextureArrayDiffuse4.Sample(PassSrg::LinearSampler, decalUV); + normalMap = ViewSrg::m_decalTextureArrayNormalMaps4.Sample(PassSrg::LinearSampler, decalUV); + break; } float opacity = baseMap.a * decal.m_opacity * GetDecalAttenuation(surface.normal, decalRot[2], decal.m_angleAttenuation); - surface.albedo = lerp(surface.albedo, baseMap.rgb, opacity); + surface.albedo = lerp(surface.albedo, baseMap.rgb, opacity); + + float3 normalMapWS = GetWorldSpaceNormal(normalMap, decalRot[2], decalRot[0], decalRot[1], 1.0f); + surface.normal = normalize(lerp(surface.normal, normalMapWS, opacity)); } } diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/Decals/ViewSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/Decals/ViewSrg.azsli index 16b23432e1..260614b0f7 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/Decals/ViewSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/Decals/ViewSrg.azsli @@ -31,12 +31,18 @@ partial ShaderResourceGroup ViewSrg // e.g. m_decalTextureArray0 might store 24 textures @128x128, // m_decalTextureArray1 might store 16 * 256x256 // and m_decalTextureArray2 might store 4 @ 512x512 - - Texture2DArray m_decalTextureArray0; - Texture2DArray m_decalTextureArray1; - Texture2DArray m_decalTextureArray2; - Texture2DArray m_decalTextureArray3; - Texture2DArray m_decalTextureArray4; + // This must match the variable NumTextureArrays in DecalTextureArrayFeatureProcessor.h + Texture2DArray m_decalTextureArrayDiffuse0; + Texture2DArray m_decalTextureArrayDiffuse1; + Texture2DArray m_decalTextureArrayDiffuse2; + Texture2DArray m_decalTextureArrayDiffuse3; + Texture2DArray m_decalTextureArrayDiffuse4; + + Texture2DArray m_decalTextureArrayNormalMaps0; + Texture2DArray m_decalTextureArrayNormalMaps1; + Texture2DArray m_decalTextureArrayNormalMaps2; + Texture2DArray m_decalTextureArrayNormalMaps3; + Texture2DArray m_decalTextureArrayNormalMaps4; uint m_decalCount; } diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.cpp b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.cpp index ebdc884ecf..87ac0a9679 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.cpp @@ -5,7 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ - #include "DecalTextureArray.h" #include #include @@ -24,7 +23,16 @@ namespace AZ { namespace { - static const char* BaseColorTextureMapName = "baseColor.textureMap"; + static AZ::Name GetMapName(const DecalMapType mapType) + { + // Using local static to avoid cost of creating AZ::Name. Also so that this can be called from other static functions + static AZStd::array mapNames = + { + AZ::Name("baseColor.textureMap"), + AZ::Name("normal.textureMap") + }; + return mapNames[mapType]; + } static AZ::Data::AssetId GetImagePoolId() { @@ -40,6 +48,7 @@ namespace AZ return asset; } + // Extract exactly which texture asset we need to load from the given material and map type (diffuse, normal, etc). static AZ::Data::Asset GetStreamingImageAsset(const AZ::RPI::MaterialAsset& materialAsset, const AZ::Name& propertyName) { if (!materialAsset.IsReady()) @@ -78,11 +87,6 @@ namespace AZ const AZ::RPI::MaterialAsset* materialAsset = materialAssetData.GetAs(); return GetStreamingImageAsset(*materialAsset, propertyName); } - - AZ::Data::Asset GetBaseColorImageAsset(const AZ::Data::Asset materialAssetData) - { - return GetStreamingImageAsset(materialAssetData, AZ::Name(BaseColorTextureMapName)); - } } int DecalTextureArray::FindMaterial(const AZ::Data::AssetId materialAssetId) const @@ -103,7 +107,7 @@ namespace AZ { AZ_Error("DecalTextureArray", FindMaterial(materialAssetId) == -1, "Adding material when it already exists in the array"); // Invalidate the existing texture array, as we need to repack it taking into account the new material. - m_textureArrayPacked = nullptr; + AZStd::fill(m_textureArrayPacked.begin(), m_textureArrayPacked.end(), nullptr); MaterialData materialData; materialData.m_materialAssetId = materialAssetId; @@ -122,42 +126,42 @@ namespace AZ return m_materials[index].m_materialAssetId; } - RHI::Size DecalTextureArray::GetImageDimensions() const + RHI::Size DecalTextureArray::GetImageDimensions(const DecalMapType mapType) const { AZ_Assert(m_materials.size() > 0, "GetImageDimensions() cannot be called until at least one material has been added"); const int iter = m_materials.begin(); // All textures in a texture array must have the same size, so just pick the first const MaterialData& firstMaterial = m_materials[iter]; - const auto& baseColorAsset = GetBaseColorImageAsset(firstMaterial.m_materialAssetData); + const auto& baseColorAsset = GetStreamingImageAsset(firstMaterial.m_materialAssetData, GetMapName(mapType)); return baseColorAsset->GetImageDescriptor().m_size; } - const AZ::Data::Instance& DecalTextureArray::GetPackedTexture() const + const AZ::Data::Instance& DecalTextureArray::GetPackedTexture(const DecalMapType mapType) const { - return m_textureArrayPacked; + return m_textureArrayPacked[mapType]; } bool DecalTextureArray::IsValidDecalMaterial(const AZ::RPI::MaterialAsset& materialAsset) { - return GetStreamingImageAsset(materialAsset, AZ::Name(BaseColorTextureMapName)).IsReady(); + return GetStreamingImageAsset(materialAsset, GetMapName(DecalMapType_Diffuse)).IsReady(); } - AZ::Data::Asset DecalTextureArray::BuildPackedMipChainAsset(const size_t numTexturesToCreate) + AZ::Data::Asset DecalTextureArray::BuildPackedMipChainAsset(const DecalMapType mapType, const size_t numTexturesToCreate) { RPI::ImageMipChainAssetCreator assetCreator; - const uint32_t mipLevels = GetNumMipLevels(); + const uint32_t mipLevels = GetNumMipLevels(mapType); - assetCreator.Begin(Data::AssetId(AZ::Uuid::CreateRandom()), static_cast(mipLevels), aznumeric_cast(numTexturesToCreate)); + assetCreator.Begin(Data::AssetId(AZ::Uuid::CreateRandom()), aznumeric_cast(mipLevels), aznumeric_cast(numTexturesToCreate)); for (uint32_t mipLevel = 0; mipLevel < mipLevels; ++mipLevel) { - const auto& layout = GetLayout(mipLevel); + const auto& layout = GetLayout(mapType, mipLevel); assetCreator.BeginMip(layout); for (int i = 0; i < m_materials.array_size(); ++i) { - const auto rawData = GetRawImageData(i, mipLevel); - assetCreator.AddSubImage(rawData.data(), rawData.size()); + const auto imageData = GetRawImageData(GetMapName(mapType), i, mipLevel); + assetCreator.AddSubImage(imageData.data(), imageData.size()); } assetCreator.EndMip(); @@ -169,10 +173,12 @@ namespace AZ return AZStd::move(asset); } - RHI::ImageDescriptor DecalTextureArray::CreatePackedImageDescriptor(const uint16_t arraySize, const uint16_t mipLevels) const + RHI::ImageDescriptor DecalTextureArray::CreatePackedImageDescriptor( + const DecalMapType mapType, const uint16_t arraySize, const uint16_t mipLevels) const { - const RHI::Size imageDimensions = GetImageDimensions(); - RHI::ImageDescriptor imageDescriptor = RHI::ImageDescriptor::Create2DArray(RHI::ImageBindFlags::ShaderRead, imageDimensions.m_width, imageDimensions.m_height, arraySize, GetFormat()); + const RHI::Size imageDimensions = GetImageDimensions(mapType); + RHI::ImageDescriptor imageDescriptor = RHI::ImageDescriptor::Create2DArray( + RHI::ImageBindFlags::ShaderRead, imageDimensions.m_width, imageDimensions.m_height, arraySize, GetFormat(mapType)); imageDescriptor.m_mipLevels = mipLevels; return imageDescriptor; } @@ -189,21 +195,34 @@ namespace AZ } const size_t numTexturesToCreate = m_materials.array_size(); - const auto mipChainAsset = BuildPackedMipChainAsset(numTexturesToCreate); - RHI::ImageViewDescriptor imageViewDescriptor; - imageViewDescriptor.m_isArray = true; + for (int i = 0; i < DecalMapType_Num; ++i) + { + const DecalMapType mapType = aznumeric_cast(i); + if (!AreAllTextureMapsPresent(mapType)) + { + AZ_Warning("DecalTextureArray", true, "Missing decal texture maps for %s. Please make sure all maps of this type are present.\n", GetMapName(mapType).GetCStr()); + m_textureArrayPacked[i] = nullptr; + continue; + } - RPI::StreamingImageAssetCreator assetCreator; - assetCreator.Begin(Data::AssetId(Uuid::CreateRandom())); - assetCreator.SetPoolAssetId(GetImagePoolId()); - assetCreator.SetFlags(RPI::StreamingImageFlags::None); - assetCreator.SetImageDescriptor(CreatePackedImageDescriptor(aznumeric_cast(numTexturesToCreate), GetNumMipLevels())); - assetCreator.SetImageViewDescriptor(imageViewDescriptor); - assetCreator.AddMipChainAsset(*mipChainAsset); - Data::Asset packedAsset; - const bool createdOk = assetCreator.End(packedAsset); - AZ_Error("TextureArrayData", createdOk, "Pack() call failed."); - m_textureArrayPacked = createdOk ? RPI::StreamingImage::FindOrCreate(packedAsset) : nullptr; + const auto mipChainAsset = BuildPackedMipChainAsset(mapType, numTexturesToCreate); + RHI::ImageViewDescriptor imageViewDescriptor; + imageViewDescriptor.m_isArray = true; + + RPI::StreamingImageAssetCreator assetCreator; + assetCreator.Begin(Data::AssetId(Uuid::CreateRandom())); + assetCreator.SetPoolAssetId(GetImagePoolId()); + assetCreator.SetFlags(RPI::StreamingImageFlags::None); + assetCreator.SetImageDescriptor( + CreatePackedImageDescriptor(mapType, aznumeric_cast(numTexturesToCreate), GetNumMipLevels(mapType))); + assetCreator.SetImageViewDescriptor(imageViewDescriptor); + assetCreator.AddMipChainAsset(*mipChainAsset); + Data::Asset packedAsset; + const bool createdOk = assetCreator.End(packedAsset); + AZ_Error("TextureArrayData", createdOk, "Pack() call failed."); + m_textureArrayPacked[i] = createdOk ? RPI::StreamingImage::FindOrCreate(packedAsset) : nullptr; + + } // Free unused memory ClearAssets(); @@ -225,29 +244,30 @@ namespace AZ } } - uint16_t DecalTextureArray::GetNumMipLevels() const + uint16_t DecalTextureArray::GetNumMipLevels(const DecalMapType mapType) const { AZ_Assert(m_materials.size() > 0, "GetNumMipLevels() cannot be called until at least one material has been added"); // All decals in a texture array must have the same number of mips, so just pick the first const int iter = m_materials.begin(); const MaterialData& firstMaterial = m_materials[iter]; - const auto& baseColorAsset = GetBaseColorImageAsset(firstMaterial.m_materialAssetData); - return baseColorAsset->GetImageDescriptor().m_mipLevels; + const auto& imageAsset = GetStreamingImageAsset(firstMaterial.m_materialAssetData, GetMapName(mapType)); + return imageAsset->GetImageDescriptor().m_mipLevels; } - RHI::ImageSubresourceLayout DecalTextureArray::GetLayout(int mip) const + RHI::ImageSubresourceLayout DecalTextureArray::GetLayout(const DecalMapType mapType, int mip) const { AZ_Assert(m_materials.size() > 0, "GetLayout() cannot be called unless at least one material has been added"); const int iter = m_materials.begin(); - const auto& descriptor = GetBaseColorImageAsset(m_materials[iter].m_materialAssetData)->GetImageDescriptor(); + const auto& descriptor = + GetStreamingImageAsset(m_materials[iter].m_materialAssetData, GetMapName(mapType))->GetImageDescriptor(); RHI::Size mipSize = descriptor.m_size; mipSize.m_width >>= mip; mipSize.m_height >>= mip; return AZ::RHI::GetImageSubresourceLayout(mipSize, descriptor.m_format); } - AZStd::array_view DecalTextureArray::GetRawImageData(int arrayLevel, const int mip) const + AZStd::array_view DecalTextureArray::GetRawImageData(const AZ::Name& mapName, int arrayLevel, const int mip) const { // We always want to provide valid data to the AssetCreator for each texture. // If this spot in the array is empty, just provide some random image as filler. @@ -257,17 +277,20 @@ namespace AZ { arrayLevel = m_materials.begin(); } - - const auto image = GetBaseColorImageAsset(m_materials[arrayLevel].m_materialAssetData); + const auto image = GetStreamingImageAsset(m_materials[arrayLevel].m_materialAssetData, mapName); + if (!image) + { + return {}; + } const auto srcData = image->GetSubImageData(mip, 0); return srcData; } - AZ::RHI::Format DecalTextureArray::GetFormat() const + AZ::RHI::Format DecalTextureArray::GetFormat(const DecalMapType mapType) const { AZ_Assert(m_materials.size() > 0, "GetFormat() can only be called after at least one material has been added."); const int iter = m_materials.begin(); - const auto& baseColorAsset = GetBaseColorImageAsset(m_materials[iter].m_materialAssetData); + const auto& baseColorAsset = GetStreamingImageAsset(m_materials[iter].m_materialAssetData, GetMapName(mapType)); return baseColorAsset->GetImageDescriptor().m_format; } @@ -290,6 +313,25 @@ namespace AZ return id.IsValid() && materialData.m_materialAssetData.IsReady(); } + bool DecalTextureArray::AreAllTextureMapsPresent(const DecalMapType mapType) const + { + int iter = m_materials.begin(); + while (iter != -1) + { + if (!IsTextureMapPresentInMaterial(m_materials[iter], mapType)) + { + return false; + } + iter = m_materials.next(iter); + } + return true; + } + + bool DecalTextureArray::IsTextureMapPresentInMaterial(const MaterialData& materialData, const DecalMapType mapType) const + { + return GetStreamingImageAsset(materialData.m_materialAssetData, GetMapName(mapType)).IsReady(); + } + void DecalTextureArray::ClearAssets() { int iter = m_materials.begin(); @@ -330,7 +372,8 @@ namespace AZ if (m_materials.size() == 0) return false; - return m_textureArrayPacked == nullptr; + // We pack all diffuse/normal/etc in one go, so just check to see if the diffusemaps need packing + return m_textureArrayPacked[DecalMapType_Diffuse] == nullptr; } } diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.h b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.h index eb0f825e08..97bd8b9cbe 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.h +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.h @@ -28,8 +28,18 @@ namespace AZ namespace Render { + enum DecalMapType : uint32_t + { + DecalMapType_Diffuse, + DecalMapType_Normal, + DecalMapType_Num + }; + //! Helper class used by DecalTextureArrayFeatureProcessor. //! Given a set of images (all with the same dimensions and format), it can pack them together into a single textureArray that can be sent to the GPU. + //! Note that once textures are packed, this class will release any material references + //! This might free memory if nothing else is holding onto them + //! The class DOES keep note of which material asset ids were added, so it can load them again if necessary if the whole thing needs to be repacked class DecalTextureArray : public Data::AssetBus::MultiHandler { public: @@ -40,8 +50,12 @@ namespace AZ AZ::Data::AssetId GetMaterialAssetId(const int index) const; + // Packs all the added materials into one texture array per DecalMapType. void Pack(); - const Data::Instance& GetPackedTexture() const; + + // Note that we pack each type into a separate texture array. This is because formats are + // often different (BC5 for normals, BC7 for diffuse, etc) + const Data::Instance& GetPackedTexture(const DecalMapType mapType) const; static bool IsValidDecalMaterial(const RPI::MaterialAsset& materialAsset); @@ -56,22 +70,25 @@ namespace AZ void OnAssetReady(Data::Asset asset) override; + // Returns the index of the material in the m_materials container. -1 if not present. int FindMaterial(const AZ::Data::AssetId materialAssetId) const; // packs the contents of the source images into a texture array readable by the GPU and returns it - AZ::Data::Asset BuildPackedMipChainAsset(const size_t numTexturesToCreate); + AZ::Data::Asset BuildPackedMipChainAsset(const DecalMapType mapType, const size_t numTexturesToCreate); + RHI::ImageDescriptor CreatePackedImageDescriptor(const DecalMapType mapType, const uint16_t arraySize, const uint16_t mipLevels) const; - RHI::ImageDescriptor CreatePackedImageDescriptor(const uint16_t arraySize, const uint16_t mipLevels) const; - - uint16_t GetNumMipLevels() const; - RHI::Size GetImageDimensions() const; - RHI::Format GetFormat() const; - RHI::ImageSubresourceLayout GetLayout(int mip) const; - AZStd::array_view GetRawImageData(int arrayLevel, int mip) const; + uint16_t GetNumMipLevels(const DecalMapType mapType) const; + RHI::Size GetImageDimensions(const DecalMapType mapType) const; + RHI::Format GetFormat(const DecalMapType mapType) const; + RHI::ImageSubresourceLayout GetLayout(const DecalMapType mapType, int mip) const; + AZStd::array_view GetRawImageData(const AZ::Name& mapName, int arrayLevel, int mip) const; bool AreAllAssetsReady() const; bool IsAssetReady(const MaterialData& materialData) const; + bool AreAllTextureMapsPresent(const DecalMapType mapType) const; + bool IsTextureMapPresentInMaterial(const MaterialData& materialData, const DecalMapType mapType) const; + void ClearAssets(); void ClearAsset(MaterialData& materialData); @@ -81,7 +98,7 @@ namespace AZ bool NeedsPacking() const; IndexableList m_materials; - Data::Instance m_textureArrayPacked; + AZStd::array, DecalMapType_Num> m_textureArrayPacked; AZStd::unordered_set m_assetsCurrentlyLoading; }; diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp index c0b8f3315a..e5bf0bd9fa 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp @@ -322,13 +322,30 @@ namespace AZ void DecalTextureArrayFeatureProcessor::CacheShaderIndices() { - for (int i = 0; i < NumTextureArrays; ++i) - { - const RHI::ShaderResourceGroupLayout* viewSrgLayout = RPI::RPISystemInterface::Get()->GetViewSrgLayout().get(); - const AZStd::string baseName = "m_decalTextureArray" + AZStd::to_string(i); + // The azsl shader should define several texture arrays such as: + // Texture2DArray m_decalTextureArrayDiffuse0; + // Texture2DArray m_decalTextureArrayDiffuse1; + // Texture2DArray m_decalTextureArrayDiffuse2; + // and + // Texture2DArray m_decalTextureArrayNormalMaps0; + // Texture2DArray m_decalTextureArrayNormalMaps1; + // Texture2DArray m_decalTextureArrayNormalMaps2; + static const AZStd::array ShaderNames = { "m_decalTextureArrayDiffuse", + "m_decalTextureArrayNormalMaps" }; - m_decalTextureArrayIndices[i] = viewSrgLayout->FindShaderInputImageIndex(Name(baseName.c_str())); - AZ_Warning("DecalTextureArrayFeatureProcessor", m_decalTextureArrayIndices[i].IsValid(), "Unable to find %s in decal shader.", baseName.c_str()); + for (int mapType = 0; mapType < DecalMapType_Num; ++mapType) + { + for (int texArrayIdx = 0; texArrayIdx < NumTextureArrays; ++texArrayIdx) + { + const RHI::ShaderResourceGroupLayout* viewSrgLayout = RPI::RPISystemInterface::Get()->GetViewSrgLayout().get(); + const AZStd::string baseName = ShaderNames[mapType] + AZStd::to_string(texArrayIdx); + + m_decalTextureArrayIndices[texArrayIdx][mapType] = viewSrgLayout->FindShaderInputImageIndex(Name(baseName.c_str())); + AZ_Warning( + "DecalTextureArrayFeatureProcessor", m_decalTextureArrayIndices[texArrayIdx][mapType].IsValid(), + "Unable to find %s in decal shader.", + baseName.c_str()); + } } } @@ -411,8 +428,11 @@ namespace AZ int iter = m_textureArrayList.begin(); while (iter != -1) { - const auto& packedTexture = m_textureArrayList[iter].second.GetPackedTexture(); - view->GetShaderResourceGroup()->SetImage(m_decalTextureArrayIndices[iter], packedTexture); + for (int mapType = 0 ; mapType < DecalMapType_Num ; ++mapType) + { + const auto& packedTexture = m_textureArrayList[iter].second.GetPackedTexture(aznumeric_cast(mapType)); + view->GetShaderResourceGroup()->SetImage(m_decalTextureArrayIndices[iter][mapType], packedTexture); + } iter = m_textureArrayList.next(iter); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h index 57c5c69e0d..13a6682629 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h @@ -89,6 +89,7 @@ namespace AZ private: // Number of size and format permutations + // This number should match the number of texture arrays in Decals/ViewSrg.azsli static constexpr int NumTextureArrays = 5; static constexpr const char* FeatureProcessorName = "DecalTextureArrayFeatureProcessor"; @@ -128,7 +129,7 @@ namespace AZ // 4 textures @ 512x512 IndexableList < AZStd::pair < AZ::RHI::Size, DecalTextureArray>> m_textureArrayList; - AZStd::array m_decalTextureArrayIndices; + AZStd::array, NumTextureArrays> m_decalTextureArrayIndices; GpuBufferHandler m_decalBufferHandler; AsyncLoadTracker m_materialLoadTracker; diff --git a/Gems/Atom/Feature/Common/Code/Tests/Decals/DecalTextureArrayTests.cpp b/Gems/Atom/Feature/Common/Code/Tests/Decals/DecalTextureArrayTests.cpp index fcbcec0256..84c2b88507 100644 --- a/Gems/Atom/Feature/Common/Code/Tests/Decals/DecalTextureArrayTests.cpp +++ b/Gems/Atom/Feature/Common/Code/Tests/Decals/DecalTextureArrayTests.cpp @@ -42,7 +42,7 @@ namespace UnitTest { AZ::Render::DecalTextureArray decalTextureArray; decalTextureArray.Pack(); - auto nothing = decalTextureArray.GetPackedTexture(); + auto nothing = decalTextureArray.GetPackedTexture(AZ::Render::DecalMapType_Diffuse); EXPECT_EQ(nothing, nullptr); } From e1c49e436dab7e8ee58bd4da885736b426e201aa Mon Sep 17 00:00:00 2001 From: "rgba16f [Amazon]" <82187279+rgba16f@users.noreply.github.com> Date: Thu, 30 Sep 2021 17:45:33 -0500 Subject: [PATCH 34/50] convert atom to task graph (#4230) * Intial attempt to convert the Atom/RHI/FrameScheduler to use the new TaskGraph api Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Avoid enqueuing work on the active task thread if the submitted task graph is waitable When submitting a task graph, supplying a wait event implies that dependent jobs must occur on threads that do not wait on the event (in the absence of work stealing). This change prevents this by adding a notion of a task thread enable/disable state, and prohibiting dependent jobs from being enqueued on waiting threads. Signed-off-by: Jeremy Ong * Convert RPI/Scene to use TaskGraph pass 1, Culling jobs remain on the old system Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * RemoveTask Graph changes from the FrameScheduler::ExecuteGroups, use old job system instead Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Per review, removing commented out code Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Cleanup debug code, & build fix Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Add a cvar & interface to query whether to use jobs or task graph Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Make TaskGraph assert if you try to wait inside a job Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Fix TaskTest SpawnSubgraph to account for the new TaskGraphEvent assert on wait in a running task Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * 3 minor cleanups. 1) Events always store a ptr to their executor 2) Fix clang compile error 3) remove an early out. Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Fix double group end that was causing assert/crash plus misc minor diff's with development Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Fix deallocation failure on deactivation of the TaskGraphSystemComponent. Also make the system component account for multiple creation in Unit Tests. Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Update with PR feedback 1) Rename UseTaskGraph to IsTaskGraphActive & update related code 2) prefer TaskExecutor::SetInstance 3) add comments and remove commented out code Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Fix incorrect RTTI name for TaskGraphActiveInterface Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> * Move TaskGraphSystemComponent CRC calculation to a shared variable Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> Co-authored-by: Jeremy Ong --- Code/Framework/AzCore/AzCore/AzCoreModule.cpp | 3 + .../AzCore/AzCore/Task/TaskExecutor.cpp | 85 ++++-- .../AzCore/AzCore/Task/TaskExecutor.h | 7 +- .../AzCore/AzCore/Task/TaskGraph.cpp | 8 +- Code/Framework/AzCore/AzCore/Task/TaskGraph.h | 15 + .../AzCore/AzCore/Task/TaskGraph.inl | 10 +- .../AzCore/Task/TaskGraphSystemComponent.cpp | 88 ++++++ .../AzCore/Task/TaskGraphSystemComponent.h | 47 +++ .../AzCore/AzCore/azcore_files.cmake | 2 + Code/Framework/AzCore/Tests/TaskTests.cpp | 84 +++++- .../AzFramework/Application/Application.cpp | 2 + .../Code/Include/Atom/RHI/FrameScheduler.h | 3 + .../RHI/Code/Source/RHI/FrameScheduler.cpp | 119 ++++++-- .../Code/Source/RHI/AsyncUploadQueue.cpp | 1 + .../RPI/Code/Include/Atom/RPI.Public/Scene.h | 19 ++ .../Atom/RPI/Code/Source/RPI.Public/Scene.cpp | 281 ++++++++++++++---- .../001_DefaultWhite.material | 4 +- .../002_BaseColorLerp.material | 4 +- 18 files changed, 652 insertions(+), 130 deletions(-) create mode 100644 Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp create mode 100644 Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.h diff --git a/Code/Framework/AzCore/AzCore/AzCoreModule.cpp b/Code/Framework/AzCore/AzCore/AzCoreModule.cpp index c60ea1bd72..ec45335f95 100644 --- a/Code/Framework/AzCore/AzCore/AzCoreModule.cpp +++ b/Code/Framework/AzCore/AzCore/AzCoreModule.cpp @@ -22,6 +22,7 @@ #include #include #include +#include namespace AZ { @@ -41,6 +42,7 @@ namespace AZ TimeSystemComponent::CreateDescriptor(), LoggerSystemComponent::CreateDescriptor(), EventSchedulerSystemComponent::CreateDescriptor(), + TaskGraphSystemComponent::CreateDescriptor(), #if !defined(AZCORE_EXCLUDE_LUA) ScriptSystemComponent::CreateDescriptor(), @@ -55,6 +57,7 @@ namespace AZ azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), + azrtti_typeid(), }; } } diff --git a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp index 2bb88fbfa2..d2d19d1359 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp +++ b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp @@ -190,11 +190,13 @@ namespace AZ class TaskWorker { public: - void Spawn(::AZ::TaskExecutor& executor, size_t id, AZStd::semaphore& initSemaphore, bool affinitize) + static thread_local TaskWorker* t_worker; + + void Spawn(::AZ::TaskExecutor& executor, uint32_t id, AZStd::semaphore& initSemaphore, bool affinitize) { m_executor = &executor; - AZStd::string threadName = AZStd::string::format("TaskWorker %zu", id); + AZStd::string threadName = AZStd::string::format("TaskWorker %u", id); AZStd::thread_desc desc = {}; desc.m_name = threadName.c_str(); if (affinitize) @@ -205,12 +207,29 @@ namespace AZ m_thread = AZStd::thread{ [this, &initSemaphore] { + t_worker = this; initSemaphore.release(); Run(); }, &desc }; } + // Threads that wait on a graph to complete are disqualified from receiving tasks until the wait finishes + void Disable() + { + m_enabled = false; + } + + void Enable() + { + m_enabled = true; + } + + bool Enabled() const + { + return m_enabled; + } + void Join() { m_active.store(false, AZStd::memory_order_release); @@ -222,11 +241,7 @@ namespace AZ { m_queue.Enqueue(task); - if (!m_busy.exchange(true)) - { - // The worker was idle prior to enqueueing the task, release the semaphore - m_semaphore.release(); - } + m_semaphore.release(); } private: @@ -234,7 +249,6 @@ namespace AZ { while (m_active) { - m_busy = false; m_semaphore.acquire(); if (!m_active) @@ -242,8 +256,6 @@ namespace AZ return; } - m_busy = true; - Task* task = m_queue.TryDequeue(); while (task) { @@ -271,12 +283,15 @@ namespace AZ AZStd::thread m_thread; AZStd::atomic m_active; - AZStd::atomic m_busy; + AZStd::atomic m_enabled = true; AZStd::binary_semaphore m_semaphore; ::AZ::TaskExecutor* m_executor; TaskQueue m_queue; + friend class ::AZ::TaskExecutor; }; + + thread_local TaskWorker* TaskWorker::t_worker = nullptr; } // namespace Internal static EnvironmentVariable s_executor; @@ -291,13 +306,16 @@ namespace AZ return **s_executor; } - // TODO: Create the default executor as part of a component (as in TaskManagerComponent) void TaskExecutor::SetInstance(TaskExecutor* executor) { - AZ_Assert(!s_executor, "Attempting to set the global task executor more than once"); - - s_executor = AZ::Environment::CreateVariable("GlobalTaskExecutor"); - s_executor.Set(executor); + if (!executor) + { + s_executor.Reset(); + } + else if (!s_executor) // ignore any calls to set after the first (this happens in unit tests that create new system entities) + { + s_executor = AZ::Environment::CreateVariable(s_executorName, executor); + } } TaskExecutor::TaskExecutor(uint32_t threadCount) @@ -307,14 +325,12 @@ namespace AZ m_workers = reinterpret_cast(azmalloc(m_threadCount * sizeof(Internal::TaskWorker))); - bool affinitize = m_threadCount == AZStd::thread::hardware_concurrency(); - AZStd::semaphore initSemaphore; - for (size_t i = 0; i != m_threadCount; ++i) + for (uint32_t i = 0; i != m_threadCount; ++i) { new (m_workers + i) Internal::TaskWorker{}; - m_workers[i].Spawn(*this, i, initSemaphore, affinitize); + m_workers[i].Spawn(*this, i, initSemaphore, false); } for (size_t i = 0; i != m_threadCount; ++i) @@ -334,9 +350,21 @@ namespace AZ azfree(m_workers); } - void TaskExecutor::Submit(Internal::CompiledTaskGraph& graph) + Internal::TaskWorker* TaskExecutor::GetTaskWorker() + { + if (Internal::TaskWorker::t_worker && Internal::TaskWorker::t_worker->m_executor == this) + { + return Internal::TaskWorker::t_worker; + } + return nullptr; + } + + void TaskExecutor::Submit(Internal::CompiledTaskGraph& graph, TaskGraphEvent* event) { ++m_graphsRemaining; + + event->m_executor = this; // Used to validate event is not waited for inside a job + // Submit all tasks that have no inbound edges for (Internal::Task& task : graph.Tasks()) { @@ -352,11 +380,24 @@ namespace AZ // TODO: Something more sophisticated is likely needed here. // First, we are completely ignoring affinity. // Second, some heuristics on core availability will help distribute work more effectively - m_workers[++m_lastSubmission % m_threadCount].Enqueue(&task); + uint32_t nextWorker = ++m_lastSubmission % m_threadCount; + while (!m_workers[nextWorker].Enabled()) + { + // Graphs that are waiting for the completion of a task graph cannot enqueue tasks onto + // the thread issuing the wait. + nextWorker = ++m_lastSubmission % m_threadCount; + } + + m_workers[nextWorker].Enqueue(&task); } void TaskExecutor::ReleaseGraph() { --m_graphsRemaining; } + + void TaskExecutor::ReactivateTaskWorker() + { + GetTaskWorker()->Enable(); + } } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.h b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.h index dc2fa5a4c8..7e1ff80902 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.h +++ b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.h @@ -72,14 +72,19 @@ namespace AZ explicit TaskExecutor(uint32_t threadCount = 0); ~TaskExecutor(); - void Submit(Internal::CompiledTaskGraph& graph); + // Submit a task graph for execution. Waitable task graphs cannot enqueue work on the task thread + // that is currently active + void Submit(Internal::CompiledTaskGraph& graph, TaskGraphEvent* event); void Submit(Internal::Task& task); private: friend class Internal::TaskWorker; + friend class TaskGraphEvent; + Internal::TaskWorker* GetTaskWorker(); void ReleaseGraph(); + void ReactivateTaskWorker(); Internal::TaskWorker* m_workers; uint32_t m_threadCount = 0; diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp b/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp index 3fb93903c9..f57b06890a 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp +++ b/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp @@ -14,6 +14,12 @@ namespace AZ { using Internal::CompiledTaskGraph; + void TaskGraphEvent::Wait() + { + AZ_Assert(m_executor->GetTaskWorker() == nullptr, "Waiting in a task is unsupported"); + m_semaphore.acquire(); + } + void TaskToken::PrecedesInternal(TaskToken& comesAfter) { AZ_Assert(!m_parent.m_submitted, "Cannot mutate a TaskGraph that was previously submitted."); @@ -71,7 +77,7 @@ namespace AZ m_compiledTaskGraph->m_tasks[i].Init(); } - executor.Submit(*m_compiledTaskGraph); + executor.Submit(*m_compiledTaskGraph, waitEvent); if (m_retained) { diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraph.h b/Code/Framework/AzCore/AzCore/Task/TaskGraph.h index 4b454c63de..9553013a4b 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskGraph.h +++ b/Code/Framework/AzCore/AzCore/Task/TaskGraph.h @@ -22,10 +22,19 @@ namespace AZ namespace Internal { class CompiledTaskGraph; + class TaskWorker; } class TaskExecutor; class TaskGraph; + class TaskGraphActiveInterface + { + public: + AZ_RTTI(TaskGraphActiveInterface, "{08118074-B139-4EF9-B8FD-29F1D6DC9233}"); + + virtual bool IsTaskGraphActive() const = 0; + }; + // A TaskToken is returned each time a Task is added to the TaskGraph. TaskTokens are used to // express dependencies between tasks within the graph, and have no purpose after the graph // is submitted (simply let them go out of scope) @@ -70,9 +79,12 @@ namespace AZ private: friend class ::AZ::Internal::CompiledTaskGraph; friend class TaskGraph; + friend class TaskExecutor; + void Signal(); AZStd::binary_semaphore m_semaphore; + TaskExecutor* m_executor = nullptr; }; // The TaskGraph encapsulates a set of tasks and their interdependencies. After adding @@ -89,6 +101,9 @@ namespace AZ // Reset the state of the task graph to begin recording tasks and edges again // NOTE: Graph must be in a "settled" state (cannot be in-flight) void Reset(); + + // Returns false if 1 or more tasks have been added to the graph + bool IsEmpty(); // Add a task to the graph, retrieiving a token that can be used to express dependencies // between tasks. The first argument specifies the TaskKind, used for tracking the task. diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl b/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl index e0ac74ba9d..7b2f0cefdc 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl +++ b/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl @@ -33,11 +33,6 @@ namespace AZ return m_semaphore.try_acquire_for(AZStd::chrono::milliseconds{ 0 }); } - inline void TaskGraphEvent::Wait() - { - m_semaphore.acquire(); - } - inline void TaskGraphEvent::Signal() { m_semaphore.release(); @@ -59,6 +54,11 @@ namespace AZ return { AddTask(descriptor, AZStd::forward(lambdas))... }; } + inline bool TaskGraph::IsEmpty() + { + return m_tasks.empty(); + } + inline void TaskGraph::Detach() { m_retained = false; diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp new file mode 100644 index 0000000000..eed461ecb4 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp @@ -0,0 +1,88 @@ +/* + * 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 +#include +#include +#include +#include + +// Create a cvar as a central location for experimentation with switching from the Job system to TaskGraph system. +AZ_CVAR(bool, cl_activateTaskGraph, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Flag clients of TaskGraph to switch between jobs/taskgraph (Note does not disable task graph system)"); +static constexpr uint32_t TaskExecutorServiceCrc = AZ_CRC_CE("TaskExecutorService"); + +namespace AZ +{ + void TaskGraphSystemComponent::Activate() + { + AZ_Assert(m_taskExecutor == nullptr, "Error multiple activation of the TaskGraphSystemComponent"); + + if (Interface::Get() == nullptr) + { + Interface::Register(this); + m_taskExecutor = aznew TaskExecutor(); + TaskExecutor::SetInstance(m_taskExecutor); + } + } + + void TaskGraphSystemComponent::Deactivate() + { + if (&TaskExecutor::Instance() == m_taskExecutor) // check that our instance is the global instance (not always true in unit tests) + { + m_taskExecutor->SetInstance(nullptr); + } + if (m_taskExecutor) + { + azdestroy(m_taskExecutor); + m_taskExecutor = nullptr; + } + if (Interface::Get() == this) + { + Interface::Unregister(this); + } + } + + void TaskGraphSystemComponent::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(TaskExecutorServiceCrc); + } + + void TaskGraphSystemComponent::GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible) + { + incompatible.push_back(TaskExecutorServiceCrc); + } + + void TaskGraphSystemComponent::GetDependentServices([[maybe_unused]] ComponentDescriptor::DependencyArrayType& dependent) + { + } + + void TaskGraphSystemComponent::Reflect(ReflectContext* context) + { + if (SerializeContext* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(1) + ; + + if (AZ::EditContext* ec = serializeContext->GetEditContext()) + { + ec->Class + ("TaskGraph", "System component to create the default executor") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Category, "Engine") + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System")) + ; + } + } + } + + bool TaskGraphSystemComponent::IsTaskGraphActive() const + { + return cl_activateTaskGraph; + } +} // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.h b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.h new file mode 100644 index 0000000000..a4c6da9539 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include +#include +#include + +namespace AZ +{ + class TaskGraphSystemComponent + : public Component + , public TaskGraphActiveInterface + { + public: + AZ_COMPONENT(AZ::TaskGraphSystemComponent, "{5D56B829-1FEB-43D5-A0BD-E33C0497EFE2}") + + TaskGraphSystemComponent() = default; + + // Implement TaskGraphActiveInterface + bool IsTaskGraphActive() const override; + + private: + ////////////////////////////////////////////////////////////////////////// + // Component base + void Activate() override; + void Deactivate() override; + ////////////////////////////////////////////////////////////////////////// + + /// \ref ComponentDescriptor::GetProvidedServices + static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided); + /// \ref ComponentDescriptor::GetIncompatibleServices + static void GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible); + /// \ref ComponentDescriptor::GetDependentServices + static void GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent); + /// \red ComponentDescriptor::Reflect + static void Reflect(ReflectContext* reflection); + + AZ::TaskExecutor* m_taskExecutor = nullptr; + }; +} diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index aa07959997..14579cbf33 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -633,6 +633,8 @@ set(FILES Task/TaskGraph.cpp Task/TaskGraph.h Task/TaskGraph.inl + Task/TaskGraphSystemComponent.h + Task/TaskGraphSystemComponent.cpp Threading/ThreadSafeDeque.h Threading/ThreadSafeDeque.inl Threading/ThreadSafeObject.h diff --git a/Code/Framework/AzCore/Tests/TaskTests.cpp b/Code/Framework/AzCore/Tests/TaskTests.cpp index e743ab6643..9e839f60ee 100644 --- a/Code/Framework/AzCore/Tests/TaskTests.cpp +++ b/Code/Framework/AzCore/Tests/TaskTests.cpp @@ -34,7 +34,7 @@ namespace UnitTest AZ::AllocatorInstance::Create(); AZ::AllocatorInstance::Create(); - m_executor = aznew TaskExecutor(4); + m_executor = aznew TaskExecutor(); } void TearDown() override @@ -236,6 +236,82 @@ namespace UnitTest EXPECT_EQ(x, 1); } + TEST_F(TaskGraphTestFixture, SingleTask) + { + AZStd::atomic_int32_t x = 0; + + TaskGraph graph; + graph.AddTask( + defaultTD, + [&x] + { + x = 1; + }); + + TaskGraphEvent ev; + graph.SubmitOnExecutor(*m_executor, &ev); + ev.Wait(); + + EXPECT_EQ(1, x); + } + + + TEST_F(TaskGraphTestFixture, SingleTaskChain) + { + AZStd::atomic_int32_t x = 0; + + TaskGraph graph; + auto a = graph.AddTask( + defaultTD, + [&x] + { + x += 1; + }); + auto b = graph.AddTask( + defaultTD, + [&x] + { + x += 1; + }); + b.Precedes(a); + + TaskGraphEvent ev; + graph.SubmitOnExecutor(*m_executor, &ev); + ev.Wait(); + + EXPECT_EQ(2, x); + } + + TEST_F(TaskGraphTestFixture, MultipleIndependentTaskChains) + { + AZStd::atomic_int32_t x = 0; + constexpr int numChains = 5; + + TaskGraph graph; + for( int i = 0; i < numChains; ++i) + { + auto a = graph.AddTask( + defaultTD, + [&x] + { + x += 1; + }); + auto b = graph.AddTask( + defaultTD, + [&x] + { + x += 1; + }); + b.Precedes(a); + } + + TaskGraphEvent ev; + graph.SubmitOnExecutor(*m_executor, &ev); + ev.Wait(); + + EXPECT_EQ(2*numChains, x); + } + TEST_F(TaskGraphTestFixture, VariadicInterface) { int x = 0; @@ -388,6 +464,7 @@ namespace UnitTest EXPECT_EQ(3, x); } + // Waiting inside a task is disallowed , test that it fails correctly TEST_F(TaskGraphTestFixture, SpawnSubgraph) { AZStd::atomic x = 0; @@ -434,7 +511,10 @@ namespace UnitTest f.Precedes(g); TaskGraphEvent ev; subgraph.SubmitOnExecutor(*m_executor, &ev); + // TaskGraphEvent::Wait asserts if called on a worker thread, suppress & validate assert + AZ_TEST_START_TRACE_SUPPRESSION; ev.Wait(); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); }); auto d = graph.AddTask( defaultTD, @@ -464,8 +544,6 @@ namespace UnitTest TaskGraphEvent ev; graph.SubmitOnExecutor(*m_executor, &ev); ev.Wait(); - - EXPECT_EQ(3 | 0b100000, x); } TEST_F(TaskGraphTestFixture, RetainedGraph) diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp index 12974d03cf..5c7398a95c 100644 --- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp +++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -295,6 +296,7 @@ namespace AzFramework azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), + azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameScheduler.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameScheduler.h index ddcee53e69..48e7e0f339 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameScheduler.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameScheduler.h @@ -23,6 +23,7 @@ namespace AZ { class Job; + class TaskGraphActiveInterface; namespace RHI { @@ -228,6 +229,8 @@ namespace AZ // list of RayTracingShaderTables that should be built this frame AZStd::vector> m_rayTracingShaderTablesToBuild; + + AZ::TaskGraphActiveInterface* m_taskGraphActive = nullptr; }; } } diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp index 5d2feb1e34..3363675d0e 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp @@ -25,9 +25,11 @@ #include #include +#include #include #include #include +#include namespace AZ { @@ -77,6 +79,8 @@ namespace AZ m_rootScope = m_rootScopeProducer->GetScope(); m_device = &device; + m_taskGraphActive = AZ::Interface::Get(); + m_lastFrameEndTime = AZStd::GetTimeNowTicks(); return ResultCode::Success; @@ -85,6 +89,7 @@ namespace AZ void FrameScheduler::Shutdown() { m_device = nullptr; + m_taskGraphActive = nullptr; m_rootScopeProducer = nullptr; m_rootScope = nullptr; m_frameGraphExecuter = nullptr; @@ -258,50 +263,98 @@ namespace AZ if (m_compileRequest.m_jobPolicy == JobPolicy::Parallel) { - const auto compileGroupsBeginFunction = [](ShaderResourceGroupPool* srgPool) - { - srgPool->CompileGroupsBegin(); - }; - - resourcePoolDatabase.ForEachShaderResourceGroupPool(compileGroupsBeginFunction); - // Iterate over each SRG pool and fork jobs to compile SRGs. const uint32_t compilesPerJob = m_compileRequest.m_shaderResourceGroupCompilesPerJob; - AZ::JobCompletion jobCompletion; - - const auto compileIntervalsFunction = [compilesPerJob, &jobCompletion](ShaderResourceGroupPool* srgPool) + if (m_taskGraphActive && m_taskGraphActive->IsTaskGraphActive()) { - const uint32_t compilesInPool = srgPool->GetGroupsToCompileCount(); - const uint32_t jobCount = DivideByMultiple(compilesInPool, compilesPerJob); + AZ::TaskGraph taskGraph; - for (uint32_t i = 0; i < jobCount; ++i) + const auto compileIntervalsFunction = [compilesPerJob, &taskGraph](ShaderResourceGroupPool* srgPool) { - Interval interval; - interval.m_min = i * compilesPerJob; - interval.m_max = AZStd::min(interval.m_min + compilesPerJob, compilesInPool); + srgPool->CompileGroupsBegin(); + const uint32_t compilesInPool = srgPool->GetGroupsToCompileCount(); + const uint32_t jobCount = DivideByMultiple(compilesInPool, compilesPerJob); + AZ::TaskDescriptor srgCompileDesc{"SrgCompile", "Graphics"}; + AZ::TaskDescriptor srgCompileEndDesc{"SrgCompileEnd", "Graphics"}; - const auto compileGroupsForIntervalLambda = [srgPool, interval]() + auto srgCompileEndTask = taskGraph.AddTask( + srgCompileEndDesc, + [srgPool]() + { + srgPool->CompileGroupsEnd(); + }); + + for (uint32_t i = 0; i < jobCount; ++i) { - AZ_PROFILE_SCOPE(RHI, "FrameScheduler : compileGroupsForIntervalLambda"); - srgPool->CompileGroupsForInterval(interval); - }; + Interval interval; + interval.m_min = i * compilesPerJob; + interval.m_max = AZStd::min(interval.m_min + compilesPerJob, compilesInPool); - AZ::Job* executeGroupJob = AZ::CreateJobFunction(AZStd::move(compileGroupsForIntervalLambda), true, nullptr); - executeGroupJob->SetDependent(&jobCompletion); - executeGroupJob->Start(); + auto compileTask = taskGraph.AddTask( + srgCompileDesc, + [srgPool, interval]() + { + AZ_PROFILE_SCOPE(RHI, "FrameScheduler : compileGroupsForIntervalLambda"); + srgPool->CompileGroupsForInterval(interval); + }); + compileTask.Precedes(srgCompileEndTask); + } + }; + + resourcePoolDatabase.ForEachShaderResourceGroupPool(AZStd::move(compileIntervalsFunction)); + if (!taskGraph.IsEmpty()) + { + AZ::TaskGraphEvent finishedEvent; + taskGraph.Submit(&finishedEvent); + finishedEvent.Wait(); } - }; - - resourcePoolDatabase.ForEachShaderResourceGroupPool(AZStd::move(compileIntervalsFunction)); - - jobCompletion.StartAndWaitForCompletion(); - - const auto compileGroupsEndFunction = [](ShaderResourceGroupPool* srgPool) + } + else // use Job system { - srgPool->CompileGroupsEnd(); - }; + const auto compileGroupsBeginFunction = [](ShaderResourceGroupPool* srgPool) + { + srgPool->CompileGroupsBegin(); + }; - resourcePoolDatabase.ForEachShaderResourceGroupPool(compileGroupsEndFunction); + resourcePoolDatabase.ForEachShaderResourceGroupPool(compileGroupsBeginFunction); + + // Iterate over each SRG pool and fork jobs to compile SRGs. + AZ::JobCompletion jobCompletion; + + const auto compileIntervalsFunction = [compilesPerJob, &jobCompletion](ShaderResourceGroupPool* srgPool) + { + const uint32_t compilesInPool = srgPool->GetGroupsToCompileCount(); + const uint32_t jobCount = DivideByMultiple(compilesInPool, compilesPerJob); + + for (uint32_t i = 0; i < jobCount; ++i) + { + Interval interval; + interval.m_min = i * compilesPerJob; + interval.m_max = AZStd::min(interval.m_min + compilesPerJob, compilesInPool); + + const auto compileGroupsForIntervalLambda = [srgPool, interval]() + { + AZ_PROFILE_SCOPE(RHI, "FrameScheduler : compileGroupsForIntervalLambda"); + srgPool->CompileGroupsForInterval(interval); + }; + + AZ::Job* executeGroupJob = AZ::CreateJobFunction(AZStd::move(compileGroupsForIntervalLambda), true, nullptr); + executeGroupJob->SetDependent(&jobCompletion); + executeGroupJob->Start(); + } + }; + + resourcePoolDatabase.ForEachShaderResourceGroupPool(AZStd::move(compileIntervalsFunction)); + + jobCompletion.StartAndWaitForCompletion(); + + const auto compileGroupsEndFunction = [](ShaderResourceGroupPool* srgPool) + { + srgPool->CompileGroupsEnd(); + }; + + resourcePoolDatabase.ForEachShaderResourceGroupPool(compileGroupsEndFunction); + } } else { diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/AsyncUploadQueue.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/AsyncUploadQueue.cpp index bd163f1419..eadd571452 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/AsyncUploadQueue.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/AsyncUploadQueue.cpp @@ -33,6 +33,7 @@ namespace AZ // Use separate work submission queue from the hw copy queue to avoid the per frame sync. m_copyQueue = CommandQueue::Create(); + m_copyQueue->SetName(AZ::Name("AsyncUpload Queue")); RHI::CommandQueueDescriptor commandQueueDescriptor; commandQueueDescriptor.m_hardwareQueueClass = RHI::HardwareQueueClass::Copy; 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 b1c6aac92d..fc81368331 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -194,6 +195,9 @@ namespace AZ // This function is called every time scene's render pipelines change. void RebuildPipelineStatesLookup(); + // Helper function to wait for end of TaskGraph + void WaitTGEvent(AZ::TaskGraphEvent& completionTGEvent, AZStd::atomic_bool* workToWaitOn = nullptr); + // Helper function for wait and clean up a completion job void WaitAndCleanCompletionJob(AZ::JobCompletion*& completionJob); @@ -204,12 +208,26 @@ namespace AZ // This happens in UpdateSrgs() void PrepareSceneSrg(); + // Implementation functions that allow scene to switch between using Jobs or TaskGraphs + void SimulateTaskGraph(); + void SimulateJobs(); + + void CollectDrawPacketsTaskGraph(); + void CollectDrawPacketsJobs(); + + void FinalizeDrawListsTaskGraph(); + void FinalizeDrawListsJobs(); + // List of feature processors that are active for this scene AZStd::vector m_featureProcessors; // List of pipelines of this scene. Each pipeline has an unique pipeline Id. AZStd::vector m_pipelines; + // CPU simulation TaskGraphEvent to wait for completion of all the simulation tasks + AZ::TaskGraphEvent m_simulationFinishedTGEvent; + AZStd::atomic_bool m_simulationFinishedWorkActive = false; + // CPU simulation job completion for track all feature processors' simulation jobs AZ::JobCompletion* m_simulationCompletion = nullptr; @@ -228,6 +246,7 @@ namespace AZ SceneId m_id; bool m_activated = false; + bool m_taskGraphActive = false; // update during tick, to ensure it only changes on frame boundaries RenderPipelinePtr m_defaultPipeline; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index 646cba1999..c5d82c6f29 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -23,6 +23,8 @@ #include #include +#include + #include namespace AZ @@ -92,7 +94,14 @@ namespace AZ Scene::~Scene() { - WaitAndCleanCompletionJob(m_simulationCompletion); + if (m_taskGraphActive) + { + WaitTGEvent(m_simulationFinishedTGEvent, &m_simulationFinishedWorkActive); + } + else + { + WaitAndCleanCompletionJob(m_simulationCompletion); + } SceneRequestBus::Handler::BusDisconnect(); // Remove all the render pipelines. Need to process queued changes with pass system before and after remove render pipelines @@ -346,6 +355,47 @@ namespace AZ return nullptr; } + void Scene::SimulateTaskGraph() + { + static const AZ::TaskDescriptor simulationTGDesc{"RPI::Scene::Simulate", "Graphics"}; + AZ::TaskGraph simulationTG; + + for (FeatureProcessorPtr& fp : m_featureProcessors) + { + FeatureProcessor* featureProcessor = fp.get(); + simulationTG.AddTask( + simulationTGDesc, + [this, featureProcessor]() + { + featureProcessor->Simulate(m_simulatePacket); + }); + } + simulationTG.Detach(); + m_simulationFinishedWorkActive = true; + simulationTG.Submit(&m_simulationFinishedTGEvent); + } + + void Scene::SimulateJobs() + { + // Create a new job to track completion. + m_simulationCompletion = aznew AZ::JobCompletion(); + + for (FeatureProcessorPtr& fp : m_featureProcessors) + { + FeatureProcessor* featureProcessor = fp.get(); + const auto jobLambda = [this, featureProcessor]() + { + + featureProcessor->Simulate(m_simulatePacket); + }; + + AZ::Job* simulationJob = AZ::CreateJobFunction(AZStd::move(jobLambda), true, nullptr); //auto-deletes + simulationJob->SetDependent(m_simulationCompletion); + simulationJob->Start(); + } + //[GFX TODO]: the completion job should start here + } + void Scene::Simulate([[maybe_unused]] const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy) { AZ_PROFILE_SCOPE(RPI, "Scene: Simulate"); @@ -353,7 +403,17 @@ namespace AZ m_simulationTime = tickInfo.m_currentGameTime; // If previous simulation job wasn't done, wait for it to finish. - WaitAndCleanCompletionJob(m_simulationCompletion); + if (m_taskGraphActive) + { + WaitTGEvent(m_simulationFinishedTGEvent, &m_simulationFinishedWorkActive); + } + else + { + WaitAndCleanCompletionJob(m_simulationCompletion); + } + + auto taskGraphActiveInterface = AZ::Interface::Get(); + m_taskGraphActive = taskGraphActiveInterface && taskGraphActiveInterface->IsTaskGraphActive(); if (jobPolicy == RHI::JobPolicy::Serial) { @@ -364,22 +424,27 @@ namespace AZ } else { - // Create a new job to track completion. - m_simulationCompletion = aznew AZ::JobCompletion(); - - for (FeatureProcessorPtr& fp : m_featureProcessors) + if (m_taskGraphActive) { - FeatureProcessor* featureProcessor = fp.get(); - const auto jobLambda = [this, featureProcessor]() - { - featureProcessor->Simulate(m_simulatePacket); - }; - - AZ::Job* simulationJob = AZ::CreateJobFunction(AZStd::move(jobLambda), true, nullptr); //auto-deletes - simulationJob->SetDependent(m_simulationCompletion); - simulationJob->Start(); + SimulateTaskGraph(); } - //[GFX TODO]: the completion job should start here + else + { + SimulateJobs(); + } + } + } + + void Scene::WaitTGEvent(AZ::TaskGraphEvent& completionTGEvent, AZStd::atomic_bool* workToWaitOn ) + { + AZ_PROFILE_SCOPE(RPI, "Scene: WaitAndCleanCompletionJob"); + if (!workToWaitOn || workToWaitOn->load()) + { + completionTGEvent.Wait(); + } + if (workToWaitOn) + { + workToWaitOn->store(false); } } @@ -394,7 +459,7 @@ namespace AZ completionJob = nullptr; } } - + void Scene::ConnectEvent(PrepareSceneSrgEvent::Handler& handler) { handler.Connect(m_prepareSrgEvent); @@ -418,12 +483,139 @@ namespace AZ } } + void Scene::CollectDrawPacketsTaskGraph() + { + AZ_PROFILE_SCOPE(RPI, "CollectDrawPackets"); + AZ::TaskGraphEvent collectDrawPacketsTGEvent; + static const AZ::TaskDescriptor collectDrawPacketsTGDesc{"RPI_Scene_PrepareRender_CollectDrawPackets", "Graphics"}; + + AZ::TaskGraph collectDrawPacketsTG; + // Launch FeatureProcessor::Render() jobs + for (auto& fp : m_featureProcessors) + { + collectDrawPacketsTG.AddTask( + collectDrawPacketsTGDesc, + [this, &fp]() + { + fp->Render(m_renderPacket); + }); + + } + collectDrawPacketsTG.Submit(&collectDrawPacketsTGEvent); + + // Launch CullingSystem::ProcessCullables() jobs (will run concurrently with FeatureProcessor::Render() jobs if m_parallelOctreeTraversal) + bool parallelOctreeTraversal = m_cullingScene->GetDebugContext().m_parallelOctreeTraversal; + m_cullingScene->BeginCulling(m_renderPacket.m_views); + AZ::JobCompletion processCullablesCompletion; + for (ViewPtr& viewPtr : m_renderPacket.m_views) + { + AZ::Job* processCullablesJob = AZ::CreateJobFunction([this, &viewPtr](AZ::Job& thisJob) + { + m_cullingScene->ProcessCullables(*this, *viewPtr, thisJob); // can't call directly because ProcessCullables needs a parent job + }, + true, nullptr); //auto-deletes + if (parallelOctreeTraversal) + { + processCullablesJob->SetDependent(&processCullablesCompletion); + processCullablesJob->Start(); + } + else + { + processCullablesJob->StartAndWaitForCompletion(); + } + } + + WaitTGEvent(collectDrawPacketsTGEvent); + processCullablesCompletion.StartAndWaitForCompletion(); + } + + void Scene::CollectDrawPacketsJobs() + { + AZ_PROFILE_SCOPE(RPI, "CollectDrawPackets"); + AZ::JobCompletion* collectDrawPacketsCompletion = aznew AZ::JobCompletion(); + + // Launch FeatureProcessor::Render() jobs + for (auto& fp : m_featureProcessors) + { + const auto renderLambda = [this, &fp]() + { + fp->Render(m_renderPacket); + }; + + AZ::Job* renderJob = AZ::CreateJobFunction(AZStd::move(renderLambda), true, nullptr); //auto-deletes + renderJob->SetDependent(collectDrawPacketsCompletion); + renderJob->Start(); + } + + // Launch CullingSystem::ProcessCullables() jobs (will run concurrently with FeatureProcessor::Render() jobs) + m_cullingScene->BeginCulling(m_renderPacket.m_views); + for (ViewPtr& viewPtr : m_renderPacket.m_views) + { + AZ::Job* processCullablesJob = AZ::CreateJobFunction([this, &viewPtr](AZ::Job& thisJob) + { + m_cullingScene->ProcessCullables(*this, *viewPtr, thisJob); // can't call directly because ProcessCullables needs a parent job + }, + true, nullptr); //auto-deletes + if (m_cullingScene->GetDebugContext().m_parallelOctreeTraversal) + { + processCullablesJob->SetDependent(collectDrawPacketsCompletion); + processCullablesJob->Start(); + } + else + { + processCullablesJob->StartAndWaitForCompletion(); + } + } + + WaitAndCleanCompletionJob(collectDrawPacketsCompletion); + } + + void Scene::FinalizeDrawListsTaskGraph() + { + AZ::TaskGraphEvent finalizeDrawListsTGEvent; + static const AZ::TaskDescriptor finalizeDrawListsTGDesc{"RPI_Scene_PrepareRender_FinalizeDrawLists", "Graphics"}; + + AZ::TaskGraph finalizeDrawListsTG; + for (auto& view : m_renderPacket.m_views) + { + finalizeDrawListsTG.AddTask( + finalizeDrawListsTGDesc, + [view]() + { + view->FinalizeDrawLists(); + }); + } + finalizeDrawListsTG.Submit(&finalizeDrawListsTGEvent); + WaitTGEvent(finalizeDrawListsTGEvent); + } + + void Scene::FinalizeDrawListsJobs() + { + AZ::JobCompletion* finalizeDrawListsCompletion = aznew AZ::JobCompletion(); + for (auto& view : m_renderPacket.m_views) + { + const auto finalizeDrawListsLambda = [view]() + { + view->FinalizeDrawLists(); + }; + + AZ::Job* finalizeDrawListsJob = AZ::CreateJobFunction(AZStd::move(finalizeDrawListsLambda), true, nullptr); //auto-deletes + finalizeDrawListsJob->SetDependent(finalizeDrawListsCompletion); + finalizeDrawListsJob->Start(); + } + WaitAndCleanCompletionJob(finalizeDrawListsCompletion); + } + void Scene::PrepareRender(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy) { AZ_PROFILE_SCOPE(RPI, "Scene: PrepareRender"); + if (m_taskGraphActive) + { + WaitTGEvent(m_simulationFinishedTGEvent, &m_simulationFinishedWorkActive); + } + else { - AZ_PROFILE_SCOPE(RPI, "WaitForSimulationCompletion"); WaitAndCleanCompletionJob(m_simulationCompletion); } @@ -496,44 +688,16 @@ namespace AZ } { - AZ_PROFILE_SCOPE(RPI, "CollectDrawPackets"); - AZ::JobCompletion* collectDrawPacketsCompletion = aznew AZ::JobCompletion(); - // Launch FeatureProcessor::Render() jobs - for (auto& fp : m_featureProcessors) + if (m_taskGraphActive) { - const auto renderLambda = [this, &fp]() - { - fp->Render(m_renderPacket); - }; - - AZ::Job* renderJob = AZ::CreateJobFunction(AZStd::move(renderLambda), true, nullptr); //auto-deletes - renderJob->SetDependent(collectDrawPacketsCompletion); - renderJob->Start(); + CollectDrawPacketsTaskGraph(); } - - // Launch CullingSystem::ProcessCullables() jobs (will run concurrently with FeatureProcessor::Render() jobs) - m_cullingScene->BeginCulling(m_renderPacket.m_views); - for (ViewPtr& viewPtr : m_renderPacket.m_views) + else { - AZ::Job* processCullablesJob = AZ::CreateJobFunction([this, &viewPtr](AZ::Job& thisJob) - { - m_cullingScene->ProcessCullables(*this, *viewPtr, thisJob); - }, - true, nullptr); //auto-deletes - if (m_cullingScene->GetDebugContext().m_parallelOctreeTraversal) - { - processCullablesJob->SetDependent(collectDrawPacketsCompletion); - processCullablesJob->Start(); - } - else - { - processCullablesJob->StartAndWaitForCompletion(); - } + CollectDrawPacketsJobs(); } - WaitAndCleanCompletionJob(collectDrawPacketsCompletion); - m_cullingScene->EndCulling(); // Add dynamic draw data for all the views @@ -556,20 +720,15 @@ namespace AZ } else { - AZ::JobCompletion* finalizeDrawListsCompletion = aznew AZ::JobCompletion(); - for (auto& view : m_renderPacket.m_views) + if (m_taskGraphActive) { - const auto finalizeDrawListsLambda = [view]() - { - view->FinalizeDrawLists(); - }; - - AZ::Job* finalizeDrawListsJob = AZ::CreateJobFunction(AZStd::move(finalizeDrawListsLambda), true, nullptr); //auto-deletes - finalizeDrawListsJob->SetDependent(finalizeDrawListsCompletion); - finalizeDrawListsJob->Start(); + FinalizeDrawListsTaskGraph(); + } + else + { + FinalizeDrawListsJobs(); } AZ_PROFILE_END(RPI); - WaitAndCleanCompletionJob(finalizeDrawListsCompletion); } } diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/001_DefaultWhite.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/001_DefaultWhite.material index 8fe732cb09..2e4eee7f8e 100644 --- a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/001_DefaultWhite.material +++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/001_DefaultWhite.material @@ -1,6 +1,6 @@ { "description": "", - "materialType": "Materials\\Types\\StandardPBR.materialtype", + "materialType": "Materials/Types/StandardPBR.materialtype", "parentMaterial": "", "propertyLayoutVersion": 3 -} +} \ No newline at end of file diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/002_BaseColorLerp.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/002_BaseColorLerp.material index 8509e08d78..f8214e1b2e 100644 --- a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/002_BaseColorLerp.material +++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/002_BaseColorLerp.material @@ -1,6 +1,6 @@ { "description": "", - "materialType": "Materials\\Types\\StandardPBR.materialtype", + "materialType": "Materials/Types/StandardPBR.materialtype", "parentMaterial": "", "propertyLayoutVersion": 3, "properties": { @@ -16,4 +16,4 @@ "textureMap": "TestData/Textures/TextureHaven/4k_castle_brick_02_red/4k_castle_brick_02_red_hp_bc.png" } } -} +} \ No newline at end of file From 79dea539c40729a5d148479efb93e89f750529dd Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Mon, 26 Jul 2021 13:28:54 -0500 Subject: [PATCH 35/50] Allow user to specify a partial gpu name to the forceAdaptor command line argument Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp | 16 +++++++++++----- .../Source/RPI.Private/RPISystemComponent.cpp | 1 + .../RPI/Code/Source/RPI.Public/RPISystem.cpp | 1 + 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp index ad3ab119ef..bf29efc644 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp @@ -18,6 +18,7 @@ #include #include #include +#include AZ_DEFINE_BUDGET(RHI); @@ -101,6 +102,8 @@ namespace AZ } AZStd::string preferredUserAdapterName = RHI::GetCommandLineValue("forceAdapter"); + AZStd::to_lower(preferredUserAdapterName.begin(), preferredUserAdapterName.end()); + bool findPreferredUserDevice = preferredUserAdapterName.size() > 0; RHI::PhysicalDevice* preferredUserDevice{}; RHI::PhysicalDevice* preferredVendorDevice{}; @@ -110,12 +113,15 @@ namespace AZ const RHI::PhysicalDeviceDescriptor& descriptor = physicalDevice->GetDescriptor(); AZ_Printf("RHISystem", "\tEnumerated physical device: %s\n", descriptor.m_description.c_str()); - - if (!preferredUserDevice && descriptor.m_description == preferredUserAdapterName) + if (findPreferredUserDevice) { - preferredUserDevice = physicalDevice.get(); + AZStd::string descriptorLowerCase = descriptor.m_description; + AZStd::to_lower( descriptorLowerCase.begin(), descriptorLowerCase.end()); + if (!preferredUserDevice && descriptorLowerCase.contains(preferredUserAdapterName)) + { + preferredUserDevice = physicalDevice.get(); + } } - // Record the first nVidia or AMD device we find. if (!preferredVendorDevice && (descriptor.m_vendorId == RHI::VendorId::AMD || descriptor.m_vendorId == RHI::VendorId::nVidia)) { @@ -123,7 +129,7 @@ namespace AZ } } - AZ_Warning("RHISystem", preferredUserAdapterName.empty() || preferredUserDevice, "Specified adapter name not found: '%s'", preferredUserAdapterName.c_str()); + AZ_Warning("RHI", preferredUserAdapterName.empty() || preferredUserDevice, "Specified adapter name not found: '%s'", preferredUserAdapterName.c_str()); RHI::PhysicalDevice* physicalDeviceFound{}; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp b/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp index 2567d221e5..8c78ff0e73 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp @@ -56,6 +56,7 @@ namespace AZ void RPISystemComponent::GetRequiredServices(ComponentDescriptor::DependencyArrayType& required) { required.push_back(RHI::Factory::GetComponentService()); + required.push_back(AZ_CRC_CE("LoggerService")); } void RPISystemComponent::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp index 5df1c655d6..5e57ba4e00 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp @@ -79,6 +79,7 @@ namespace AZ void RPISystem::Initialize(const RPISystemDescriptor& rpiSystemDescriptor) { + AZ_Printf("RHI", "RPISystem Initialize\n"); m_rhiSystem.InitDevice(); // Gather asset handlers from sub-systems. From de224d236007f74f77c4ee905a26aaf88e316c9b Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Thu, 30 Sep 2021 17:45:29 -0500 Subject: [PATCH 36/50] Removed minor string differences Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp | 2 +- Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp index bf29efc644..744b688c60 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp @@ -129,7 +129,7 @@ namespace AZ } } - AZ_Warning("RHI", preferredUserAdapterName.empty() || preferredUserDevice, "Specified adapter name not found: '%s'", preferredUserAdapterName.c_str()); + AZ_Warning("RHISystem", preferredUserAdapterName.empty() || preferredUserDevice, "Specified adapter name not found: '%s'", preferredUserAdapterName.c_str()); RHI::PhysicalDevice* physicalDeviceFound{}; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp index 5e57ba4e00..5df1c655d6 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp @@ -79,7 +79,6 @@ namespace AZ void RPISystem::Initialize(const RPISystemDescriptor& rpiSystemDescriptor) { - AZ_Printf("RHI", "RPISystem Initialize\n"); m_rhiSystem.InitDevice(); // Gather asset handlers from sub-systems. From 04d62ae76171c6d79d0fdc3d496532f5a4d98f04 Mon Sep 17 00:00:00 2001 From: dmcdiar Date: Thu, 30 Sep 2021 15:59:06 -0700 Subject: [PATCH 37/50] Passed DiffuseProbeGrid OBB directly into culling data. Signed-off-by: dmcdiar --- .../Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp index a966eaddcb..b4f91e58d9 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp @@ -831,7 +831,7 @@ namespace AZ aabbWs.GetAsSphere(center, radius); m_cullable.m_cullData.m_boundingSphere = Sphere(center, radius); - m_cullable.m_cullData.m_boundingObb = aabbWs.GetTransformedObb(AZ::Transform::CreateIdentity()); + m_cullable.m_cullData.m_boundingObb = m_obbWs; m_cullable.m_cullData.m_visibilityEntry.m_boundingVolume = aabbWs; m_cullable.m_cullData.m_visibilityEntry.m_userData = &m_cullable; m_cullable.m_cullData.m_visibilityEntry.m_typeFlags = AzFramework::VisibilityEntry::TYPE_RPI_Cullable; From 0b718d435c63e5f3f5f16f5d64be7be559b18c55 Mon Sep 17 00:00:00 2001 From: Mike Chang Date: Thu, 30 Sep 2021 17:40:34 -0700 Subject: [PATCH 38/50] Installer, bootstrapper, and executable signing for Windows (#4406) * Added a codesigning script to pre and post build steps in the Windows installer CD job * Changed `windows_installer` job name to `installer_vs2019` * Added `installer-nightly` tag for `installer_vs2019` * Updated `build_config.json` to use an envvar for the installer url and bucket Signed-off-by: Mike Chang --- .../Platform/Windows/PackagingPostBuild.cmake | 44 ++++++++- .../Platform/Windows/PackagingPreBuild.cmake | 37 +++++++ .../Platform/Windows/Packaging_windows.cmake | 5 +- .../build/Platform/Windows/build_config.json | 12 ++- scripts/signer/Platform/Windows/signer.ps1 | 99 +++++++++++++++++++ 5 files changed, 189 insertions(+), 8 deletions(-) create mode 100644 cmake/Platform/Windows/PackagingPreBuild.cmake create mode 100644 scripts/signer/Platform/Windows/signer.ps1 diff --git a/cmake/Platform/Windows/PackagingPostBuild.cmake b/cmake/Platform/Windows/PackagingPostBuild.cmake index 5e09743373..377a9fb221 100644 --- a/cmake/Platform/Windows/PackagingPostBuild.cmake +++ b/cmake/Platform/Windows/PackagingPostBuild.cmake @@ -32,6 +32,9 @@ set(_addtional_defines -dCPACK_RESOURCE_PATH=${CPACK_SOURCE_DIR}/Platform/Windows/Packaging ) +file(REAL_PATH "${CPACK_SOURCE_DIR}/.." _root_path) +file(TO_NATIVE_PATH "${_root_path}/scripts/signer/Platform/Windows/signer.ps1" _sign_script) + if(CPACK_LICENSE_URL) list(APPEND _addtional_defines -dCPACK_LICENSE_URL=${CPACK_LICENSE_URL}) endif() @@ -55,6 +58,30 @@ set(_light_command -o "${_bootstrap_output_file}" ) +set(_signing_command + psexec.exe + -accepteula + -nobanner + -s + powershell.exe + -NoLogo + -ExecutionPolicy Bypass + -File ${_sign_script} +) + +message(STATUS "Signing package files in ${_cpack_wix_out_dir}") +execute_process( + COMMAND ${_signing_command} -packagePath ${_cpack_wix_out_dir} + RESULT_VARIABLE _signing_result + ERROR_VARIABLE _signing_errors + OUTPUT_VARIABLE _signing_output + ECHO_OUTPUT_VARIABLE +) + +if(NOT ${_signing_result} EQUAL 0) + message(FATAL_ERROR "An error occurred during signing package files. ${_signing_errors}") +endif() + message(STATUS "Creating Bootstrap Installer...") execute_process( COMMAND ${_candle_command} @@ -80,6 +107,19 @@ file(COPY ${_bootstrap_output_file} message(STATUS "Bootstrap installer generated to ${CPACK_PACKAGE_DIRECTORY}/${_bootstrap_filename}") +message(STATUS "Signing bootstrap installer in ${CPACK_PACKAGE_DIRECTORY}") +execute_process( + COMMAND ${_signing_command} -bootstrapPath ${CPACK_PACKAGE_DIRECTORY}/${_bootstrap_filename} + RESULT_VARIABLE _signing_result + ERROR_VARIABLE _signing_errors + OUTPUT_VARIABLE _signing_output + ECHO_OUTPUT_VARIABLE +) + +if(NOT ${_signing_result} EQUAL 0) + message(FATAL_ERROR "An error occurred during signing bootstrap installer. ${_signing_errors}") +endif() + # use the internal default path if somehow not specified from cpack_configure_downloads if(NOT CPACK_UPLOAD_DIRECTORY) set(CPACK_UPLOAD_DIRECTORY ${CPACK_PACKAGE_DIRECTORY}/CPackUploads) @@ -100,11 +140,9 @@ if(NOT CPACK_UPLOAD_URL) return() endif() -file(REAL_PATH "${CPACK_SOURCE_DIR}/.." _root_path) - +file(TO_NATIVE_PATH "${_cpack_wix_out_dir}" _cpack_wix_out_dir) file(TO_NATIVE_PATH "${_root_path}/python/python.cmd" _python_cmd) file(TO_NATIVE_PATH "${_root_path}/scripts/build/tools/upload_to_s3.py" _upload_script) -file(TO_NATIVE_PATH "${_cpack_wix_out_dir}" _cpack_wix_out_dir) function(upload_to_s3 in_url in_local_path in_file_regex) diff --git a/cmake/Platform/Windows/PackagingPreBuild.cmake b/cmake/Platform/Windows/PackagingPreBuild.cmake new file mode 100644 index 0000000000..d3924c7a02 --- /dev/null +++ b/cmake/Platform/Windows/PackagingPreBuild.cmake @@ -0,0 +1,37 @@ +# +# 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 +# +# + +file(REAL_PATH "${CPACK_SOURCE_DIR}/.." _root_path) +set(_cpack_wix_out_dir ${CPACK_TOPLEVEL_DIRECTORY}) +file(TO_NATIVE_PATH "${_root_path}/scripts/signer/Platform/Windows/signer.ps1" _sign_script) + +set(_signing_command + psexec.exe + -accepteula + -nobanner + -s + powershell.exe + -NoLogo + -ExecutionPolicy Bypass + -File ${_sign_script} +) + +message(STATUS "Signing executable files in ${_cpack_wix_out_dir}") +execute_process( + COMMAND ${_signing_command} -exePath ${_cpack_wix_out_dir} + RESULT_VARIABLE _signing_result + ERROR_VARIABLE _signing_errors + OUTPUT_VARIABLE _signing_output + ECHO_OUTPUT_VARIABLE +) + +if(NOT ${_signing_result} EQUAL 0) + message(FATAL_ERROR "An error occurred during signing executable files. ${_signing_errors}") +endif() + +message(STATUS "Signing exes complete!") diff --git a/cmake/Platform/Windows/Packaging_windows.cmake b/cmake/Platform/Windows/Packaging_windows.cmake index 5bb9928b61..ced7757852 100644 --- a/cmake/Platform/Windows/Packaging_windows.cmake +++ b/cmake/Platform/Windows/Packaging_windows.cmake @@ -108,7 +108,6 @@ set(_raw_text_license [[ ]]) if(LY_INSTALLER_DOWNLOAD_URL) - set(WIX_THEME_WARNING_IMAGE ${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/warning.png) if(LY_INSTALLER_LICENSE_URL) @@ -138,6 +137,10 @@ if(LY_INSTALLER_DOWNLOAD_URL) # the bootstrapper will at the very least need a different upgrade guid generate_wix_guid(CPACK_WIX_BOOTSTRAP_UPGRADE_GUID "${_guid_seed_base}_Bootstrap_UpgradeCode") + set(CPACK_PRE_BUILD_SCRIPTS + ${CPACK_SOURCE_DIR}/Platform/Windows/PackagingPreBuild.cmake + ) + set(CPACK_POST_BUILD_SCRIPTS ${CPACK_SOURCE_DIR}/Platform/Windows/PackagingPostBuild.cmake ) diff --git a/scripts/build/Platform/Windows/build_config.json b/scripts/build/Platform/Windows/build_config.json index 3848e6f980..e33025a4d9 100644 --- a/scripts/build/Platform/Windows/build_config.json +++ b/scripts/build/Platform/Windows/build_config.json @@ -351,17 +351,21 @@ "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" } }, - "windows_installer": { + "installer_vs2019": { "TAGS": [ - "nightly-clean" + "nightly-clean", + "nightly-installer" ], + "PIPELINE_ENV":{ + "NODE_LABEL":"windows-packaging" + }, "COMMAND": "build_installer_windows.cmd", "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE -DLY_VERSION_ENGINE_NAME=o3de-sdk -DLY_INSTALLER_WIX_ROOT=\"!WIX! \"", - "EXTRA_CMAKE_OPTIONS": "-DLY_INSTALLER_AUTO_GEN_TAG=ON -DLY_INSTALLER_DOWNLOAD_URL=https://www.o3debinaries.org -DLY_INSTALLER_LICENSE_URL=https://www.o3debinaries.org/license", - "CPACK_BUCKET": "spectra-prism-staging-us-west-2", + "EXTRA_CMAKE_OPTIONS": "-DLY_INSTALLER_AUTO_GEN_TAG=ON -DLY_INSTALLER_DOWNLOAD_URL=!INSTALLER_DOWNLOAD_URL! -DLY_INSTALLER_LICENSE_URL=!INSTALLER_DOWNLOAD_URL!/license", + "CPACK_BUCKET": "!INSTALLER_BUCKET!", "CMAKE_LY_PROJECTS": "", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" diff --git a/scripts/signer/Platform/Windows/signer.ps1 b/scripts/signer/Platform/Windows/signer.ps1 new file mode 100644 index 0000000000..5366564140 --- /dev/null +++ b/scripts/signer/Platform/Windows/signer.ps1 @@ -0,0 +1,99 @@ +# +# 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 +# +# + +param ( + [String[]] $exePath, + [String[]] $packagePath, + [String[]] $bootstrapPath, + [String[]] $certificate +) + +# Get prerequisites, certs, and paths ready +$tempPath = [System.IO.Path]::GetTempPath() # Order of operations defined here: https://docs.microsoft.com/en-us/dotnet/api/system.io.path.gettemppath?view=net-5.0&tabs=windows#remarks +$certThumbprint = Get-ChildItem -Path Cert:LocalMachine\MY -CodeSigningCert -ErrorAction Stop | Select-Object -ExpandProperty Thumbprint # Grab first certificate from local machine store + +if ($certificate) { + Write-Output "Checking certificate thumbprint $certificate" + Get-ChildItem -Path Cert:LocalMachine\MY -ErrorAction SilentlyContinue | Where-Object {$_.Thumbprint -eq $certificate} # Prints certificate Thumbprint and Subject if found + if($?) { + $certThumbprint = $certificate + } + else { + Write-Error "$certificate thumbprint not found, using $certThumbprint thumbprint instead" + } +} + +Try { + $signtoolPath = Resolve-Path "C:\Program Files*\Windows Kits\10\bin\*\x64\signtool.exe" -ErrorAction Stop | Select-Object -Last 1 -ExpandProperty Path + $insigniaPath = Resolve-Path "C:\Program Files*\WiX*\bin\insignia.exe" -ErrorAction Stop | Select-Object -Last 1 -ExpandProperty Path +} +Catch { + Write-Error "Signtool or Wix insignia not found! Exiting." +} + +function Write-Signature { + param ( + $signtool, + $thumbprint, + $filename + ) + + $attempts = 2 + $sleepSec = 5 + + Do { + $attempts-- + Try { + & $signtool sign /tr http://timestamp.digicert.com /td sha256 /fd sha256 /sha1 $thumbprint /sm $filename + & $signtool verify /pa /v $filename + return + } + Catch { + Write-Error $_.Exception.InnerException.Message -ErrorAction Continue + Start-Sleep -Seconds $sleepSec + } + } while ($attempts -lt 0) + + throw "Failed to sign $filename" # Bypassed in try block if the command is successful +} + +# Looping through each path insteaad of globbing to prevent hitting maximum command string length limit +if ($exePath) { + Write-Output "### Signing EXE files ###" + $files = @(Get-ChildItem $exePath -Recurse *.exe | % { $_.FullName }) + foreach ($file in $files) { + Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $file + } +} + +if ($packagePath) { + Write-Output "### Signing CAB files ###" + $files = @(Get-ChildItem $packagePath -Recurse *.cab | % { $_.FullName }) + foreach ($file in $files) { + Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $file + } + + Write-Output "### Signing MSI files ###" + $files = @(Get-ChildItem $packagePath -Recurse *.msi | % { $_.FullName }) + foreach ($file in $files) { + & $insigniaPath -im $files + Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $file + } +} + +if ($bootstrapPath) { + Write-Output "### Signing bootstrapper EXE ###" + $files = @(Get-ChildItem $bootstrapPath -Recurse *.exe | % { $_.FullName }) + foreach ($file in $files) { + & $insigniaPath -ib $file -o $tempPath\engine.exe + Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $tempPath\engine.exe + & $insigniaPath -ab $tempPath\engine.exe $file -o $file + Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $file + Remove-Item -Force $tempPath\engine.exe + } +} \ No newline at end of file From 46ad2f684b80443289469238b3feb803603e336d Mon Sep 17 00:00:00 2001 From: jromnoa Date: Thu, 30 Sep 2021 18:35:01 -0700 Subject: [PATCH 39/50] fixes the configurtion typo to be configuration instead and increases the test timeout to 60 sec from 30 sec Signed-off-by: jromnoa --- AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py | 6 +++--- .../Code/Source/Viewport/MaterialViewportComponent.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py index 249b9c7096..3403d8e9b1 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py @@ -226,9 +226,9 @@ class TestMaterialEditor(object): self, request, workspace, project, launcher_platform, generic_launcher, exe_file_name, cfg_args): """ Tests each valid RHI option (Null RHI excluded) can be launched with the MaterialEditor. - Checks for the "Finished loading viewport configurtions." success message post lounch. + Checks for the "Finished loading viewport configurations." success message post launch. """ - expected_lines = ["Finished loading viewport configurtions."] + expected_lines = ["Finished loading viewport configurations."] unexpected_lines = [ # "Trace::Assert", # "Trace::Error", @@ -241,7 +241,7 @@ class TestMaterialEditor(object): generic_launcher, editor_script="", run_python="--runpython", - timeout=30, + timeout=60, expected_lines=expected_lines, unexpected_lines=unexpected_lines, halt_on_unexpected=False, diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp index 24e78b5ad3..64fd7dff29 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp @@ -271,7 +271,7 @@ namespace MaterialEditor MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnEndReloadContent); - AZ_TracePrintf("Material Editor", "Finished loading viewport configurtions.\n"); + AZ_TracePrintf("Material Editor", "Finished loading viewport configurations.\n"); } AZ::Render::LightingPresetPtr MaterialViewportComponent::AddLightingPreset(const AZ::Render::LightingPreset& preset) From 18652fabeae14ea02a11148d33e99521364b936c Mon Sep 17 00:00:00 2001 From: jromnoa Date: Thu, 30 Sep 2021 18:57:37 -0700 Subject: [PATCH 40/50] fix other configurtion typos to be configuration Signed-off-by: jromnoa --- .../Code/Source/Viewport/MaterialViewportComponent.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp index 64fd7dff29..a8f41917f9 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp @@ -190,7 +190,7 @@ namespace MaterialEditor void MaterialViewportComponent::ReloadContent() { - AZ_TracePrintf("Material Editor", "Started loading viewport configurtions.\n"); + AZ_TracePrintf("Material Editor", "Started loading viewport configurations.\n"); MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnBeginReloadContent); @@ -239,7 +239,7 @@ namespace MaterialEditor { auto presetPtr = AddLightingPreset(*preset); m_lightingPresetLastSavePathMap[presetPtr] = AZ::RPI::AssetUtils::GetSourcePathByAssetId(info.m_assetId); - AZ_TracePrintf("Material Editor", "Loaded viewport configurtion: %s.\n", info.m_relativePath.c_str()); + AZ_TracePrintf("Material Editor", "Loaded viewport configuration: %s.\n", info.m_relativePath.c_str()); } } } @@ -258,7 +258,7 @@ namespace MaterialEditor { auto presetPtr = AddModelPreset(*preset); m_modelPresetLastSavePathMap[presetPtr] = AZ::RPI::AssetUtils::GetSourcePathByAssetId(info.m_assetId); - AZ_TracePrintf("Material Editor", "Loaded viewport configurtion: %s.\n", info.m_relativePath.c_str()); + AZ_TracePrintf("Material Editor", "Loaded viewport configuration: %s.\n", info.m_relativePath.c_str()); } } } From 41dbf69b46327089e95e74557f17fc42075115b0 Mon Sep 17 00:00:00 2001 From: Benjamin Jillich <43751992+amzn-jillich@users.noreply.github.com> Date: Fri, 1 Oct 2021 09:59:11 +0200 Subject: [PATCH 41/50] Animation Editor: Move real-time plugin updates from SystemComponent to the main window (#4384) Untangled the system component from editor ticking dependencies and moved it to the main window which is the more logical place for it. Signed-off-by: Benjamin Jillich --- .../EMStudioSDK/Source/MainWindow.cpp | 60 +++++++++++++++-- .../EMStudioSDK/Source/MainWindow.h | 14 +++- .../Integration/System/SystemComponent.cpp | 65 ++----------------- .../Integration/System/SystemComponent.h | 1 - 4 files changed, 74 insertions(+), 66 deletions(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp index 8ca4e1de81..06088790d9 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp @@ -69,6 +69,9 @@ AZ_PUSH_DISABLE_WARNING(4267, "-Wconversion") AZ_POP_DISABLE_WARNING #include +#include +#include + namespace EMStudio { class SaveDirtyWorkspaceCallback @@ -257,10 +260,10 @@ namespace EMStudio m_saveWorkspaceCallback = nullptr; } - - // destructor MainWindow::~MainWindow() { + DisableUpdatingPlugins(); + if (m_nativeEventFilter) { QAbstractEventDispatcher::instance()->removeNativeEventFilter(m_nativeEventFilter); @@ -577,6 +580,8 @@ namespace EMStudio AZ_Assert(!m_nativeEventFilter, "Double initialization?"); m_nativeEventFilter = new NativeEventFilter(this); QAbstractEventDispatcher::instance()->installNativeEventFilter(m_nativeEventFilter); + + EnableUpdatingPlugins(); } MainWindow::MainWindowCommandManagerCallback::MainWindowCommandManagerCallback() @@ -2813,6 +2818,53 @@ namespace EMStudio } } -} // namespace EMStudio + void MainWindow::UpdatePlugins(float timeDelta) + { + EMStudio::PluginManager* pluginManager = EMStudio::GetPluginManager(); + if (!pluginManager) + { + return; + } -#include + const size_t numPlugins = pluginManager->GetNumActivePlugins(); + for (size_t i = 0; i < numPlugins; ++i) + { + EMStudio::EMStudioPlugin* plugin = pluginManager->GetActivePlugin(i); + plugin->ProcessFrame(timeDelta); + } + } + + void MainWindow::EnableUpdatingPlugins() + { + AZ::TickBus::Handler::BusConnect(); + } + + void MainWindow::DisableUpdatingPlugins() + { + AZ::TickBus::Handler::BusDisconnect(); + } + + void MainWindow::OnTick(float delta, AZ::ScriptTimePoint timePoint) + { + AZ_UNUSED(timePoint); + + // Check if we are in game mode. + IEditor* editor = nullptr; + AzToolsFramework::EditorRequestBus::BroadcastResult(editor, &AzToolsFramework::EditorRequests::GetEditor); + const bool inGameMode = editor ? editor->IsInGameMode() : false; + + // Update all the animation editor plugins (redraw viewports, timeline, and graph windows etc). + // But only update this when the main window is visible and we are in game mode. + const bool isEditorActive = !visibleRegion().isEmpty() && !inGameMode; + + if (isEditorActive) + { + UpdatePlugins(delta); + } + } + + int MainWindow::GetTickOrder() + { + return AZ::TICK_UI; + } +} // namespace EMStudio diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.h index a11f11c6a8..585101f7d2 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.h @@ -9,6 +9,7 @@ #pragma once #if !defined(Q_MOC_RUN) +#include #include #include #include @@ -99,8 +100,9 @@ namespace EMStudio : public AzQtComponents::DockMainWindow , private PluginOptionsNotificationsBus::Router , public EMotionFX::ActorEditorRequestBus::Handler + , private AZ::TickBus::Handler { - Q_OBJECT + Q_OBJECT // AUTOMOC MCORE_MEMORYOBJECTCATEGORY(MainWindow, MCore::MCORE_DEFAULT_ALIGNMENT, MEMCATEGORY_EMSTUDIOSDK) public: @@ -304,6 +306,16 @@ namespace EMStudio MainWindowCommandManagerCallback m_mainWindowCommandManagerCallback; + private: + // AZ::TickBus::Handler overrides + void OnTick(float delta, AZ::ScriptTimePoint timePoint) override; + int GetTickOrder() override; + + void UpdatePlugins(float timeDelta); + + void EnableUpdatingPlugins(); + void DisableUpdatingPlugins(); + public slots: void OnFileOpenActor(); void OnFileSaveSelectedActors(); diff --git a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp index 56c22bb1ff..0f87c488b9 100644 --- a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp @@ -62,7 +62,6 @@ #if defined(EMOTIONFXANIMATION_EDITOR) // EMFX tools / editor includes -# include // Qt # include // EMStudio tools and main window registration @@ -603,31 +602,6 @@ namespace EMotionFX #endif } - ////////////////////////////////////////////////////////////////////////// -#if defined (EMOTIONFXANIMATION_EDITOR) - void SystemComponent::UpdateAnimationEditorPlugins(float delta) - { - if (!EMStudio::GetManager()) - { - return; - } - - EMStudio::PluginManager* pluginManager = EMStudio::GetPluginManager(); - if (!pluginManager) - { - return; - } - - // Process the plugins. - const size_t numPlugins = pluginManager->GetNumActivePlugins(); - for (size_t i = 0; i < numPlugins; ++i) - { - EMStudio::EMStudioPlugin* plugin = pluginManager->GetActivePlugin(i); - plugin->ProcessFrame(delta); - } - } -#endif - ////////////////////////////////////////////////////////////////////////// void SystemComponent::OnTick(float delta, AZ::ScriptTimePoint timePoint) { @@ -635,47 +609,18 @@ namespace EMotionFX #if defined (EMOTIONFXANIMATION_EDITOR) AZ_UNUSED(delta); - const float realDelta = m_updateTimer.StampAndGetDeltaTimeInSeconds(); + delta = m_updateTimer.StampAndGetDeltaTimeInSeconds(); +#endif // Flush events prior to updating EMotion FX. ActorNotificationBus::ExecuteQueuedEvents(); - if (CVars::emfx_updateEnabled) - { - // Main EMotionFX runtime update. - GetEMotionFX().Update(realDelta); - } - - // Check if we are in game mode. - IEditor* editor = nullptr; - EBUS_EVENT_RESULT(editor, AzToolsFramework::EditorRequests::Bus, GetEditor); - const bool inGameMode = editor ? editor->IsInGameMode() : false; - - // Update all the animation editor plugins (redraw viewports, timeline, and graph windows etc). - // But only update this when the main window is visible and we are in game mode. - const bool isEditorActive = - EMotionFX::GetEMotionFX().GetIsInEditorMode() && - EMStudio::GetManager() && - EMStudio::HasMainWindow() && - !EMStudio::GetMainWindow()->visibleRegion().isEmpty() && - !inGameMode; - - if (isEditorActive) - { - UpdateAnimationEditorPlugins(realDelta); - } -#else - // Flush events prior to updating EMotion FX. - ActorNotificationBus::ExecuteQueuedEvents(); - if (CVars::emfx_updateEnabled) { // Main EMotionFX runtime update. GetEMotionFX().Update(delta); } -#endif - const float timeDelta = delta; const ActorManager* actorManager = GetEMotionFX().GetActorManager(); const size_t numActorInstances = actorManager->GetNumActorInstances(); for (size_t i = 0; i < numActorInstances; ++i) @@ -704,7 +649,7 @@ namespace EMotionFX // If we have a physics controller. if (hasCustomMotionExtractionController || hasPhysicsController) { - const float deltaTimeInv = (timeDelta > 0.0f) ? (1.0f / timeDelta) : 0.0f; + const float deltaTimeInv = (delta > 0.0f) ? (1.0f / delta) : 0.0f; AZ::Transform currentTransform = AZ::Transform::CreateIdentity(); AZ::TransformBus::EventResult(currentTransform, entityId, &AZ::TransformBus::Events::GetWorldTM); @@ -719,7 +664,7 @@ namespace EMotionFX } else if (hasCustomMotionExtractionController) { - MotionExtractionRequestBus::Event(entityId, &MotionExtractionRequestBus::Events::ExtractMotion, positionDelta, timeDelta); + MotionExtractionRequestBus::Event(entityId, &MotionExtractionRequestBus::Events::ExtractMotion, positionDelta, delta); AZ::TransformBus::EventResult(currentTransform, entityId, &AZ::TransformBus::Events::GetWorldTM); } @@ -884,7 +829,7 @@ namespace EMotionFX // Register EMotionFX window with the main editor. AzToolsFramework::ViewPaneOptions emotionFXWindowOptions; - emotionFXWindowOptions.isPreview = true; + emotionFXWindowOptions.isPreview = false; emotionFXWindowOptions.isDeletable = true; emotionFXWindowOptions.isDockable = false; #if AZ_TRAIT_EMOTIONFX_MAIN_WINDOW_DETACHED diff --git a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.h b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.h index a716f0aa9b..5e30820ca3 100644 --- a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.h +++ b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.h @@ -108,7 +108,6 @@ namespace EMotionFX void SetMediaRoot(const char* alias); #if defined (EMOTIONFXANIMATION_EDITOR) - void UpdateAnimationEditorPlugins(float delta); void NotifyRegisterViews() override; bool IsSystemActive(EditorAnimationSystemRequests::AnimationSystem systemType) override; From fec77632efbc437394580744de0db76d917a8c85 Mon Sep 17 00:00:00 2001 From: amzn-phist <52085794+amzn-phist@users.noreply.github.com> Date: Fri, 1 Oct 2021 10:15:16 -0500 Subject: [PATCH 42/50] Archive Component - Rewrite and additional work on Archive and Asset Bundler (#4332) * Fix issues with seedlist for AutomatedTesting Fixes error reporting so it will show the file hint in the tool. Removes any missing assets from the .seed file. Remove an unnecessary dependency from AutomatedTesting dependencies file. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Make ArchiveComponent use AZ::IO::IArchive Initial changes that will get the sychronous calls in ArchiveComponent to use IArchive interface rather than external zip/7z tools. Some of the asynchronous api are still in place, anything that wasn't being used has been removed for now. This may change later if we move towards all the api being asynchronous. Until then, we can't remove the reliance upon the external archive tools completely. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Updates AZStd::thread constructors Adds a variadic constructor which forwards args to the functor. Because of our thread_desc extension, there was confusion on the arugments, so the args were reordered to take the thread_desc first, before the functor and args. Also the thread_desc is taken as reference rather than by pointer. Update callsites to account for this change. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Async operation of ArchiveComponent api This sets up the ArchiveComponent to operate asynchronously. It uses promise/future to transfer results to caller. This is still broken, there's a few things that need to get fixed up, but this is a good checkpoint for the work as it solidifies the api, cleans up a bunch of unused code, and compiles. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Removes the platform-specific ArchiveComponen These are no longer needed, as they control the direct interaction with host OS tools like 7za.exe or /bin/zip. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Removes the platform-specific files from cmake Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Removes the 7za.exe (and legal notice) This tool is no longer needed in the repo. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Fixes usage of IArchive::GetFullPath() This changed to return a PathView, updated to reflect that. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Fix promises and threads Make sure promises are only set exactly once. This meant reworking some of the initial error checking. Detach threads when created. Adds [[nodiscard]] to the functions that return a future. Since threads are detached, the future is the main way to get communication from the thread. Clean up interface, add comments. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * More edits to thread creation Changes to thread construction to account for parameter change. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Fix some remaining issues with ArchiveComponent Put created threads inside a container, then join them at Deactivate. Fix asset bundler case when injecting a file with no working directory. Fix thread constructor that applies args to a function. Fix lambdas to take string args by value rather than reference. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Fixes some remaining bugs in ArchiveComponent Open archive as read-only during extract & list operations. Fixes paths issues. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Fix initialize of opaque thread handle in thread_UnixLike.h Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed unused variable in AssetBundleComponent.cpp to fix compiler warning Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fix some issues with archives File paths in the CDR and the local headers need to match, but there were issues with path separators and case that made it possible to get invalid headers errors in some archives. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Adds some new ArchiveComponent unit tests Adds new tests for extraction of archive and adding files from a file list to an archive. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Fix file data offset issues when opening archives When opening an INestedArchive it would run through the CDR headers to create file entries in the zip cache. The offsets to the compressed data were being calculated incorrectly because they were using the CDR headers rather than jumping to the local file headers and getting offsets from those sizes. Removed and refactored some archive validation flow and zip cache factory init methods to either init default or init w/ additional validation checks. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Addresses PR feedback Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Address more points of feedback in PR Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Address additional PR feedback Fixes up some error checks and uses of strings vs paths. Enable archive component tests on Linux so we can see if they will pass. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Address PR feedback Change the INestedArchive interface to list files as AZ::IO::Path. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Disabling the ArchiveComponent tests on Linux They failed so we will revisit them to attempt a fix. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Rename a member variable to be more accurate Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Address feedback on PR Bump version of Archive Components for serialize context. Improve error messages during archive open and validation. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Revert recent changes Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- Assets/Engine/SeedAssetList.seed | 904 ------------------ .../AutomatedTesting_Dependencies.xml | 1 - .../AzCore/AzCore/IO/Streamer/Scheduler.cpp | 10 +- .../Jobs/Internal/JobManagerWorkStealing.cpp | 4 +- .../AzCore/AzCore/Task/TaskExecutor.cpp | 6 +- .../AzCore/AzCore/std/parallel/thread.h | 19 +- .../std/parallel/internal/thread_UnixLike.h | 20 +- .../std/parallel/internal/thread_WinAPI.h | 19 +- .../Framework/AzCore/Tests/AZStd/Parallel.cpp | 154 +-- Code/Framework/AzCore/Tests/Memory.cpp | 10 +- .../AzFramework/Application/Application.cpp | 16 +- .../AzFramework/Archive/Archive.cpp | 15 +- .../AzFramework/Archive/INestedArchive.h | 13 + .../AzFramework/Archive/NestedArchive.cpp | 40 + .../AzFramework/Archive/NestedArchive.h | 9 +- .../AzFramework/Archive/ZipDirCache.cpp | 13 +- .../Archive/ZipDirCacheFactory.cpp | 220 ++--- .../AzFramework/Archive/ZipDirCacheFactory.h | 28 +- .../AzFramework/Archive/ZipDirList.cpp | 4 +- .../AzFramework/Archive/ZipDirStructures.h | 35 +- .../Network/AssetProcessorConnection.cpp | 2 +- .../TargetManagementComponent.cpp | 2 +- .../AzNetworking/Utilities/TimedThread.cpp | 38 +- .../AzToolsFramework/Archive/ArchiveAPI.h | 123 ++- .../Archive/ArchiveComponent.cpp | 874 ++++++++++------- .../Archive/ArchiveComponent.h | 90 +- .../Archive/NullArchiveComponent.cpp | 113 +-- .../Archive/NullArchiveComponent.h | 44 +- .../AssetBundle/AssetBundleComponent.cpp | 27 +- .../AssetBundle/AssetBundleComponent.h | 2 +- .../Archive/ArchiveComponent_Linux.cpp | 230 ----- .../Platform/Linux/platform_linux_files.cmake | 1 - .../Archive/ArchiveComponent_Mac.cpp | 263 ----- .../Platform/Mac/platform_mac_files.cmake | 1 - .../Archive/ArchiveComponent_Windows.cpp | 167 ---- .../Windows/platform_windows_files.cmake | 1 - .../AzToolsFramework/Tests/ArchiveTests.cpp | 126 ++- .../GridMate/GridMate/Carrier/Carrier.cpp | 2 +- .../GridMate/Carrier/SocketDriver.cpp | 2 +- .../source/models/SeedListTableModel.cpp | 3 +- .../AssetBuilder/AssetBuilderComponent.cpp | 2 +- .../AssetCatalog/AssetCatalogUnitTests.cpp | 4 +- .../native/utilities/AssetServerHandler.cpp | 24 +- .../RemoteConsole/Core/RemoteConsoleCore.cpp | 2 +- .../RHI/Code/Source/RHI/AsyncWorkQueue.cpp | 2 +- .../Atom/RHI/Code/Source/RHI/CommandQueue.cpp | 2 +- Gems/Atom/RHI/Code/Source/RHI/Fence.cpp | 4 +- .../Shader/ShaderVariantAsyncLoader.cpp | 5 +- .../Code/Source/Engine/AudioSystem.cpp | 2 +- .../Code/Source/BarrierInputClient.cpp | 2 +- .../Code/Source/HttpRequestManager.cpp | 2 +- .../LevelBuilder/LevelBuilderWorker.cpp | 35 +- .../MicrophoneSystemComponent_Windows.cpp | 2 +- .../Code/Tests/PhysXMultithreadingTest.cpp | 2 +- .../Code/Source/SaveDataSystemComponent.cpp | 28 +- Tools/7za.exe | 3 - Tools/7za_legal_notice.txt | 36 - 57 files changed, 1208 insertions(+), 2600 deletions(-) delete mode 100644 Code/Framework/AzToolsFramework/Platform/Linux/AzToolsFramework/Archive/ArchiveComponent_Linux.cpp delete mode 100644 Code/Framework/AzToolsFramework/Platform/Mac/AzToolsFramework/Archive/ArchiveComponent_Mac.cpp delete mode 100644 Code/Framework/AzToolsFramework/Platform/Windows/AzToolsFramework/Archive/ArchiveComponent_Windows.cpp delete mode 100644 Tools/7za.exe delete mode 100644 Tools/7za_legal_notice.txt diff --git a/Assets/Engine/SeedAssetList.seed b/Assets/Engine/SeedAssetList.seed index 77ec509721..579fd3c444 100644 --- a/Assets/Engine/SeedAssetList.seed +++ b/Assets/Engine/SeedAssetList.seed @@ -64,30 +64,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - @@ -160,686 +136,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1384,166 +680,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1632,46 +768,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AutomatedTesting/AutomatedTesting_Dependencies.xml b/AutomatedTesting/AutomatedTesting_Dependencies.xml index 50a5caea73..98e00a2914 100644 --- a/AutomatedTesting/AutomatedTesting_Dependencies.xml +++ b/AutomatedTesting/AutomatedTesting_Dependencies.xml @@ -1,5 +1,4 @@ - \ No newline at end of file diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.cpp b/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.cpp index 9b4996ad49..9ee0fefc99 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.cpp +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.cpp @@ -43,10 +43,12 @@ namespace AZ::IO m_mainLoopDesc = threadDesc; m_mainLoopDesc.m_name = "IO Scheduler"; - m_mainLoop = AZStd::thread([this]() - { - Thread_MainLoop(); - }, &m_mainLoopDesc); + m_mainLoop = AZStd::thread( + m_mainLoopDesc, + [this]() + { + Thread_MainLoop(); + }); } } diff --git a/Code/Framework/AzCore/AzCore/Jobs/Internal/JobManagerWorkStealing.cpp b/Code/Framework/AzCore/AzCore/Jobs/Internal/JobManagerWorkStealing.cpp index f76946a667..230bf959f6 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/Internal/JobManagerWorkStealing.cpp +++ b/Code/Framework/AzCore/AzCore/Jobs/Internal/JobManagerWorkStealing.cpp @@ -644,11 +644,11 @@ JobManagerWorkStealing::ThreadList JobManagerWorkStealing::CreateWorkerThreads(c } info->m_thread = AZStd::thread( + threadDesc, [this, info]() { this->ProcessJobsWorker(info); - }, - &threadDesc + } ); info->m_threadId = info->m_thread.get_id(); diff --git a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp index d2d19d1359..7da04d7301 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp +++ b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp @@ -205,13 +205,13 @@ namespace AZ } m_active.store(true, AZStd::memory_order_release); - m_thread = AZStd::thread{ [this, &initSemaphore] + m_thread = AZStd::thread{ desc, + [this, &initSemaphore] { t_worker = this; initSemaphore.release(); Run(); - }, - &desc }; + } }; } // Threads that wait on a graph to complete are disqualified from receiving tasks until the wait finishes diff --git a/Code/Framework/AzCore/AzCore/std/parallel/thread.h b/Code/Framework/AzCore/AzCore/std/parallel/thread.h index 15d8c9dc8e..eef269c8ac 100644 --- a/Code/Framework/AzCore/AzCore/std/parallel/thread.h +++ b/Code/Framework/AzCore/AzCore/std/parallel/thread.h @@ -87,12 +87,6 @@ namespace AZStd // construct/copy/destroy: thread(); - /** - * \note thread_desc is AZStd extension. - */ - template - explicit thread(F&& f, const thread_desc* desc = 0); - ~thread(); thread(thread&& rhs) @@ -108,6 +102,15 @@ namespace AZStd return *this; } + template, thread_desc>>> + explicit thread(F&& f, Args&&... args); + + /** + * \note thread_desc is AZStd extension. + */ + template + thread(const thread_desc& desc, F&& f, Args&&... args); + // Till we fully have RVALUES template explicit thread(Internal::thread_move_t f); @@ -138,8 +141,8 @@ namespace AZStd //thread(AZStd::delegate d,const thread_desc* desc = 0); private: - thread(thread&); - thread& operator=(thread&); + thread(const thread&) = delete; + thread& operator=(const thread&) = delete; native_thread_data_type m_thread; }; diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/std/parallel/internal/thread_UnixLike.h b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/std/parallel/internal/thread_UnixLike.h index 499caebac0..d9a4982a0a 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/std/parallel/internal/thread_UnixLike.h +++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/std/parallel/internal/thread_UnixLike.h @@ -10,6 +10,8 @@ #include #include +#include + namespace AZStd { namespace Internal @@ -22,12 +24,20 @@ namespace AZStd ////////////////////////////////////////////////////////////////////////// // thread - template - inline thread::thread(F&& f, const thread_desc* desc) + template + thread::thread(F&& f, Args&&... args) + : thread(thread_desc{}, AZStd::forward(f), AZStd::forward(args)...) + {} + + template + thread::thread(const thread_desc& desc, F&& f, Args&&... args) { - Internal::thread_info* ti = Internal::create_thread_info(AZStd::forward(f)); - ti->m_name = desc ? desc->m_name : nullptr; - m_thread = Internal::create_thread(desc, ti); + auto threadfunc = [fn = AZStd::forward(f), argsTuple = AZStd::make_tuple(AZStd::forward(args)...)]() mutable -> void + { + AZStd::apply(AZStd::move(fn), AZStd::move(argsTuple)); + }; + Internal::thread_info* ti = Internal::create_thread_info(AZStd::move(threadfunc)); + m_thread = Internal::create_thread(&desc, ti); } inline bool thread::joinable() const diff --git a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/std/parallel/internal/thread_WinAPI.h b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/std/parallel/internal/thread_WinAPI.h index 46986521e7..c79381a74a 100644 --- a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/std/parallel/internal/thread_WinAPI.h +++ b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/std/parallel/internal/thread_WinAPI.h @@ -18,6 +18,8 @@ extern "C" AZ_DLL_IMPORT unsigned long __stdcall GetCurrentThreadId(void); } +#include + namespace AZStd { namespace Internal @@ -30,11 +32,20 @@ namespace AZStd ////////////////////////////////////////////////////////////////////////// // thread - template - inline thread::thread(F&& f, const thread_desc* desc) + template + thread::thread(F&& f, Args&&... args) + : thread(thread_desc{}, AZStd::forward(f), AZStd::forward(args)...) + {} + + template + thread::thread(const thread_desc& desc, F&& f, Args&&... args) { - Internal::thread_info* ti = Internal::create_thread_info(AZStd::forward(f)); - m_thread.m_handle = Internal::create_thread(desc, ti, &m_thread.m_id); + auto threadfunc = [fn = AZStd::forward(f), argsTuple = AZStd::make_tuple(AZStd::forward(args)...)]() mutable -> void + { + AZStd::apply(AZStd::move(fn), AZStd::move(argsTuple)); + }; + Internal::thread_info* ti = Internal::create_thread_info(AZStd::move(threadfunc)); + m_thread.m_handle = Internal::create_thread(&desc, ti, &m_thread.m_id); } inline bool thread::joinable() const diff --git a/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp b/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp index f3d4f58250..407cd3c258 100644 --- a/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp +++ b/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp @@ -195,18 +195,18 @@ namespace UnitTest void test_thread_id_for_running_thread_is_not_default_constructed_id() { - const thread_desc* desc = m_numThreadDesc ? &m_desc[0] : nullptr; - AZStd::thread t(AZStd::bind(&Parallel_Thread::do_nothing, this), desc); + const thread_desc desc = m_numThreadDesc ? m_desc[0] : thread_desc{}; + AZStd::thread t(desc, AZStd::bind(&Parallel_Thread::do_nothing, this)); AZ_TEST_ASSERT(t.get_id() != AZStd::thread::id()); t.join(); } void test_different_threads_have_different_ids() { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; - const thread_desc* desc2 = m_numThreadDesc ? &m_desc[1] : nullptr; - AZStd::thread t(AZStd::bind(&Parallel_Thread::do_nothing, this), desc1); - AZStd::thread t2(AZStd::bind(&Parallel_Thread::do_nothing, this), desc2); + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; + const thread_desc desc2 = m_numThreadDesc ? m_desc[1] : thread_desc{}; + AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::do_nothing, this)); + AZStd::thread t2(desc2, AZStd::bind(&Parallel_Thread::do_nothing, this)); AZ_TEST_ASSERT(t.get_id() != t2.get_id()); t.join(); t2.join(); @@ -214,13 +214,13 @@ namespace UnitTest void test_thread_ids_have_a_total_order() { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; - const thread_desc* desc2 = m_numThreadDesc ? &m_desc[1] : nullptr; - const thread_desc* desc3 = m_numThreadDesc ? &m_desc[2] : nullptr; + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; + const thread_desc desc2 = m_numThreadDesc ? m_desc[1] : thread_desc{}; + const thread_desc desc3 = m_numThreadDesc ? m_desc[2] : thread_desc{}; - AZStd::thread t(AZStd::bind(&Parallel_Thread::do_nothing, this), desc1); - AZStd::thread t2(AZStd::bind(&Parallel_Thread::do_nothing, this), desc2); - AZStd::thread t3(AZStd::bind(&Parallel_Thread::do_nothing, this), desc3); + AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::do_nothing, this)); + AZStd::thread t2(desc2, AZStd::bind(&Parallel_Thread::do_nothing, this)); + AZStd::thread t3(desc3, AZStd::bind(&Parallel_Thread::do_nothing, this)); AZ_TEST_ASSERT(t.get_id() != t2.get_id()); AZ_TEST_ASSERT(t.get_id() != t3.get_id()); AZ_TEST_ASSERT(t2.get_id() != t3.get_id()); @@ -313,10 +313,10 @@ namespace UnitTest void test_thread_id_of_running_thread_returned_by_this_thread_get_id() { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; AZStd::thread::id id; - AZStd::thread t(AZStd::bind(&Parallel_Thread::get_thread_id, this, &id), desc1); + AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::get_thread_id, this, &id)); AZStd::thread::id t_id = t.get_id(); t.join(); AZ_TEST_ASSERT(id == t_id); @@ -366,10 +366,10 @@ namespace UnitTest void test_move_on_construction() { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; AZStd::thread::id the_id; AZStd::thread x; - x = AZStd::thread(AZStd::bind(&Parallel_Thread::do_nothing_id, this, &the_id), desc1); + x = AZStd::thread(desc1, AZStd::bind(&Parallel_Thread::do_nothing_id, this, &the_id)); AZStd::thread::id x_id = x.get_id(); x.join(); AZ_TEST_ASSERT(the_id == x_id); @@ -377,8 +377,8 @@ namespace UnitTest AZStd::thread make_thread(AZStd::thread::id* the_id) { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; - return AZStd::thread(AZStd::bind(&Parallel_Thread::do_nothing_id, this, the_id), desc1); + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; + return AZStd::thread(desc1, AZStd::bind(&Parallel_Thread::do_nothing_id, this, the_id)); } void test_move_from_function_return() @@ -430,9 +430,9 @@ namespace UnitTest void do_test_creation() { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; m_data = 0; - AZStd::thread t(AZStd::bind(&Parallel_Thread::simple_thread, this), desc1); + AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::simple_thread, this)); t.join(); AZ_TEST_ASSERT(m_data == 999); } @@ -445,9 +445,9 @@ namespace UnitTest void do_test_id_comparison() { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; AZStd::thread::id self = this_thread::get_id(); - AZStd::thread thrd(AZStd::bind(&Parallel_Thread::comparison_thread, this, self), desc1); + AZStd::thread thrd(desc1, AZStd::bind(&Parallel_Thread::comparison_thread, this, self)); thrd.join(); } @@ -476,10 +476,10 @@ namespace UnitTest void do_test_creation_through_reference_wrapper() { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; non_copyable_functor f; - AZStd::thread thrd(AZStd::ref(f), desc1); + AZStd::thread thrd(desc1, AZStd::ref(f)); thrd.join(); AZ_TEST_ASSERT(f.value == 999); } @@ -491,10 +491,10 @@ namespace UnitTest void test_swap() { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; - const thread_desc* desc2 = m_numThreadDesc ? &m_desc[1] : nullptr; - AZStd::thread t(AZStd::bind(&Parallel_Thread::simple_thread, this), desc1); - AZStd::thread t2(AZStd::bind(&Parallel_Thread::simple_thread, this), desc2); + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; + const thread_desc desc2 = m_numThreadDesc ? m_desc[1] : thread_desc{}; + AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::simple_thread, this)); + AZStd::thread t2(desc2, AZStd::bind(&Parallel_Thread::simple_thread, this)); AZStd::thread::id id1 = t.get_id(); AZStd::thread::id id2 = t2.get_id(); @@ -512,7 +512,7 @@ namespace UnitTest void run() { - const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr; + const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{}; // We need to have at least one processor AZ_TEST_ASSERT(AZStd::thread::hardware_concurrency() >= 1); @@ -520,18 +520,18 @@ namespace UnitTest // Create thread to increment data till we need to m_data = 0; m_dataMax = 10; - AZStd::thread tr(AZStd::bind(&Parallel_Thread::increment_data, this), desc1); + AZStd::thread tr(desc1, AZStd::bind(&Parallel_Thread::increment_data, this)); tr.join(); AZ_TEST_ASSERT(m_data == m_dataMax); m_data = 0; - AZStd::thread trDel(make_delegate(this, &Parallel_Thread::increment_data), desc1); + AZStd::thread trDel(desc1, make_delegate(this, &Parallel_Thread::increment_data)); trDel.join(); AZ_TEST_ASSERT(m_data == m_dataMax); chrono::system_clock::time_point startTime = chrono::system_clock::now(); { - AZStd::thread tr1(AZStd::bind(&Parallel_Thread::sleep_thread, this, chrono::milliseconds(100)), desc1); + AZStd::thread tr1(desc1, AZStd::bind(&Parallel_Thread::sleep_thread, this, chrono::milliseconds(100))); tr1.join(); } auto sleepTime = chrono::system_clock::now() - startTime; @@ -563,71 +563,71 @@ namespace UnitTest { MfTest x; AZStd::function func = AZStd::bind(&MfTest::f0, &x); - AZStd::thread(func, desc1).join(); + AZStd::thread(desc1, func).join(); func = AZStd::bind(&MfTest::f0, AZStd::ref(x)); - AZStd::thread(func, desc1).join(); + AZStd::thread(desc1, func).join(); func = AZStd::bind(&MfTest::g0, &x); - AZStd::thread(func, desc1).join(); + AZStd::thread(desc1, func).join(); func = AZStd::bind(&MfTest::g0, x); - AZStd::thread(func, desc1).join(); + AZStd::thread(desc1, func).join(); func = AZStd::bind(&MfTest::g0, AZStd::ref(x)); - AZStd::thread(func, desc1).join(); + AZStd::thread(desc1, func).join(); //// 1 - //thread( AZStd::bind(&MfTest::f1, &x, 1) , desc1).join(); - //thread( AZStd::bind(&MfTest::f1, AZStd::ref(x), 1) , desc1).join(); - //thread( AZStd::bind(&MfTest::g1, &x, 1) , desc1).join(); - //thread( AZStd::bind(&MfTest::g1, x, 1) , desc1).join(); - //thread( AZStd::bind(&MfTest::g1, AZStd::ref(x), 1) , desc1).join(); + //thread( AZStd::bind(desc1, &MfTest::f1, &x, 1)).join(); + //thread( AZStd::bind(desc1, &MfTest::f1, AZStd::ref(x), 1)).join(); + //thread( AZStd::bind(desc1, &MfTest::g1, &x, 1)).join(); + //thread( AZStd::bind(desc1, &MfTest::g1, x, 1)).join(); + //thread( AZStd::bind(desc1, &MfTest::g1, AZStd::ref(x), 1)).join(); //// 2 - //thread( AZStd::bind(&MfTest::f2, &x, 1, 2) , desc1).join(); - //thread( AZStd::bind(&MfTest::f2, AZStd::ref(x), 1, 2) , desc1).join(); - //thread( AZStd::bind(&MfTest::g2, &x, 1, 2) , desc1).join(); - //thread( AZStd::bind(&MfTest::g2, x, 1, 2) , desc1).join(); - //thread( AZStd::bind(&MfTest::g2, AZStd::ref(x), 1, 2) , desc1).join(); + //thread( AZStd::bind(desc1, &MfTest::f2, &x, 1, 2)).join(); + //thread( AZStd::bind(desc1, &MfTest::f2, AZStd::ref(x), 1, 2)).join(); + //thread( AZStd::bind(desc1, &MfTest::g2, &x, 1, 2)).join(); + //thread( AZStd::bind(desc1, &MfTest::g2, x, 1, 2)).join(); + //thread( AZStd::bind(desc1, &MfTest::g2, AZStd::ref(x), 1, 2)).join(); //// 3 - //thread( AZStd::bind(&MfTest::f3, &x, 1, 2, 3) , desc1).join(); - //thread( AZStd::bind(&MfTest::f3, AZStd::ref(x), 1, 2, 3) , desc1).join(); - //thread( AZStd::bind(&MfTest::g3, &x, 1, 2, 3) , desc1).join(); - //thread( AZStd::bind(&MfTest::g3, x, 1, 2, 3) , desc1).join(); - //thread( AZStd::bind(&MfTest::g3, AZStd::ref(x), 1, 2, 3) , desc1).join(); + //thread( AZStd::bind(desc1, &MfTest::f3, &x, 1, 2, 3)).join(); + //thread( AZStd::bind(desc1, &MfTest::f3, AZStd::ref(x), 1, 2, 3)).join(); + //thread( AZStd::bind(desc1, &MfTest::g3, &x, 1, 2, 3)).join(); + //thread( AZStd::bind(desc1, &MfTest::g3, x, 1, 2, 3)).join(); + //thread( AZStd::bind(desc1, &MfTest::g3, AZStd::ref(x), 1, 2, 3)).join(); //// 4 - //thread( AZStd::bind(&MfTest::f4, &x, 1, 2, 3, 4) , desc1).join(); - //thread( AZStd::bind(&MfTest::f4, AZStd::ref(x), 1, 2, 3, 4) , desc1).join(); - //thread( AZStd::bind(&MfTest::g4, &x, 1, 2, 3, 4) , desc1).join(); - //thread( AZStd::bind(&MfTest::g4, x, 1, 2, 3, 4) , desc1).join(); - //thread( AZStd::bind(&MfTest::g4, AZStd::ref(x), 1, 2, 3, 4) , desc1).join(); + //thread( AZStd::bind(desc1, &MfTest::f4, &x, 1, 2, 3, 4)).join(); + //thread( AZStd::bind(desc1, &MfTest::f4, AZStd::ref(x), 1, 2, 3, 4)).join(); + //thread( AZStd::bind(desc1, &MfTest::g4, &x, 1, 2, 3, 4)).join(); + //thread( AZStd::bind(desc1, &MfTest::g4, x, 1, 2, 3, 4)).join(); + //thread( AZStd::bind(desc1, &MfTest::g4, AZStd::ref(x), 1, 2, 3, 4)).join(); //// 5 - //thread( AZStd::bind(&MfTest::f5, &x, 1, 2, 3, 4, 5) , desc1).join(); - //thread( AZStd::bind(&MfTest::f5, AZStd::ref(x), 1, 2, 3, 4, 5) , desc1).join(); - //thread( AZStd::bind(&MfTest::g5, &x, 1, 2, 3, 4, 5) , desc1).join(); - //thread( AZStd::bind(&MfTest::g5, x, 1, 2, 3, 4, 5) , desc1).join(); - //thread( AZStd::bind(&MfTest::g5, AZStd::ref(x), 1, 2, 3, 4, 5) , desc1).join(); + //thread( AZStd::bind(desc1, &MfTest::f5, &x, 1, 2, 3, 4, 5)).join(); + //thread( AZStd::bind(desc1, &MfTest::f5, AZStd::ref(x), 1, 2, 3, 4, 5)).join(); + //thread( AZStd::bind(desc1, &MfTest::g5, &x, 1, 2, 3, 4, 5)).join(); + //thread( AZStd::bind(desc1, &MfTest::g5, x, 1, 2, 3, 4, 5)).join(); + //thread( AZStd::bind(desc1, &MfTest::g5, AZStd::ref(x), 1, 2, 3, 4, 5)).join(); //// 6 - //thread( AZStd::bind(&MfTest::f6, &x, 1, 2, 3, 4, 5, 6) , desc1).join(); - //thread( AZStd::bind(&MfTest::f6, AZStd::ref(x), 1, 2, 3, 4, 5, 6) , desc1).join(); - //thread( AZStd::bind(&MfTest::g6, &x, 1, 2, 3, 4, 5, 6) , desc1).join(); - //thread( AZStd::bind(&MfTest::g6, x, 1, 2, 3, 4, 5, 6) , desc1).join(); - //thread( AZStd::bind(&MfTest::g6, AZStd::ref(x), 1, 2, 3, 4, 5, 6) , desc1).join(); + //thread( AZStd::bind(desc1, &MfTest::f6, &x, 1, 2, 3, 4, 5, 6)).join(); + //thread( AZStd::bind(desc1, &MfTest::f6, AZStd::ref(x), 1, 2, 3, 4, 5, 6)).join(); + //thread( AZStd::bind(desc1, &MfTest::g6, &x, 1, 2, 3, 4, 5, 6)).join(); + //thread( AZStd::bind(desc1, &MfTest::g6, x, 1, 2, 3, 4, 5, 6)).join(); + //thread( AZStd::bind(desc1, &MfTest::g6, AZStd::ref(x), 1, 2, 3, 4, 5, 6)).join(); //// 7 - //thread( AZStd::bind(&MfTest::f7, &x, 1, 2, 3, 4, 5, 6, 7), desc1).join(); - //thread( AZStd::bind(&MfTest::f7, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7), desc1).join(); - //thread( AZStd::bind(&MfTest::g7, &x, 1, 2, 3, 4, 5, 6, 7), desc1).join(); - //thread( AZStd::bind(&MfTest::g7, x, 1, 2, 3, 4, 5, 6, 7), desc1).join(); - //thread( AZStd::bind(&MfTest::g7, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7), desc1).join(); + //thread( AZStd::bind(desc1, &MfTest::f7, &x, 1, 2, 3, 4, 5, 6, 7)).join(); + //thread( AZStd::bind(desc1, &MfTest::f7, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7)).join(); + //thread( AZStd::bind(desc1, &MfTest::g7, &x, 1, 2, 3, 4, 5, 6, 7)).join(); + //thread( AZStd::bind(desc1, &MfTest::g7, x, 1, 2, 3, 4, 5, 6, 7)).join(); + //thread( AZStd::bind(desc1, &MfTest::g7, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7)).join(); //// 8 - //thread( AZStd::bind(&MfTest::f8, &x, 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join(); - //thread( AZStd::bind(&MfTest::f8, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join(); - //thread( AZStd::bind(&MfTest::g8, &x, 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join(); - //thread( AZStd::bind(&MfTest::g8, x, 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join(); - //thread( AZStd::bind(&MfTest::g8, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join(); + //thread( AZStd::bind(desc1, &MfTest::f8, &x, 1, 2, 3, 4, 5, 6, 7, 8)).join(); + //thread( AZStd::bind(desc1, &MfTest::f8, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7, 8)).join(); + //thread( AZStd::bind(desc1, &MfTest::g8, &x, 1, 2, 3, 4, 5, 6, 7, 8)).join(); + //thread( AZStd::bind(desc1, &MfTest::g8, x, 1, 2, 3, 4, 5, 6, 7, 8)).join(); + //thread( AZStd::bind(desc1, &MfTest::g8, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7, 8)).join(); AZ_TEST_ASSERT(x.m_hash == 1366); } diff --git a/Code/Framework/AzCore/Tests/Memory.cpp b/Code/Framework/AzCore/Tests/Memory.cpp index eb854050b6..5a483c1ed1 100644 --- a/Code/Framework/AzCore/Tests/Memory.cpp +++ b/Code/Framework/AzCore/Tests/Memory.cpp @@ -151,7 +151,7 @@ namespace UnitTest AZStd::thread m_threads[m_maxNumThreads]; for (unsigned int i = 0; i < m_maxNumThreads; ++i) { - m_threads[i] = AZStd::thread(AZStd::bind(&SystemAllocatorTest::ThreadFunc, this), &m_desc[i]); + m_threads[i] = AZStd::thread(m_desc[i], AZStd::bind(&SystemAllocatorTest::ThreadFunc, this)); // give some time offset to the threads so we can test alloc and dealloc at the same time. //AZStd::this_thread::sleep_for(AZStd::chrono::microseconds(500)); } @@ -286,7 +286,7 @@ namespace UnitTest AZStd::thread m_threads[m_maxNumThreads]; for (unsigned int i = 0; i < m_maxNumThreads; ++i) { - m_threads[i] = AZStd::thread(AZStd::bind(&SystemAllocatorTest::ThreadFunc, this), &m_desc[i]); + m_threads[i] = AZStd::thread(m_desc[i], AZStd::bind(&SystemAllocatorTest::ThreadFunc, this)); // give some time offset to the threads so we can test alloc and dealloc at the same time. AZStd::this_thread::sleep_for(AZStd::chrono::microseconds(500)); } @@ -724,7 +724,7 @@ namespace UnitTest AZStd::thread m_threads[m_maxNumThreads]; for (unsigned int i = 0; i < m_maxNumThreads; ++i) { - m_threads[i] = AZStd::thread(AZStd::bind(&ThreadPoolAllocatorTest::AllocDeallocFunc, this), &m_desc[i]); + m_threads[i] = AZStd::thread(m_desc[i], AZStd::bind(&ThreadPoolAllocatorTest::AllocDeallocFunc, this)); } for (unsigned int i = 0; i < m_maxNumThreads; ++i) @@ -743,12 +743,12 @@ namespace UnitTest for (unsigned int i = m_maxNumThreads/2; i c_str()); if (cache) diff --git a/Code/Framework/AzFramework/AzFramework/Archive/INestedArchive.h b/Code/Framework/AzFramework/AzFramework/Archive/INestedArchive.h index f85fd273ce..e89d16ee5d 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/INestedArchive.h +++ b/Code/Framework/AzFramework/AzFramework/Archive/INestedArchive.h @@ -11,7 +11,9 @@ #include #include +#include #include +#include #include namespace AZ::IO @@ -71,6 +73,13 @@ namespace AZ::IO // multiple times FLAGS_DONT_COMPACT = 1 << 5, + // if this is set, validate header data when opening the archive + FLAGS_VALIDATE_HEADERS = 1 << 9, + + // if this is set, validate header data when opening the archive and validate CRCs when decompressing + // & reading files. + FLAGS_FULL_VALIDATE = 1 << 10, + // Disable a pak file without unloading it, this flag is used in combination with patches and multiplayer // to ensure that specific paks stay in the position(to keep the same priority) but being disabled // when running multiplayer @@ -128,6 +137,10 @@ namespace AZ::IO // Deletes all files and directories in the archive. virtual int RemoveAll() = 0; + // Summary: + // Lists all the files in the archive. + virtual int ListAllFiles(AZStd::vector& outFileEntries) = 0; + // Summary: // Finds the file; you don't have to close the returned handle. // Returns: diff --git a/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.cpp b/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.cpp index 1e0f237df5..49a44b76fa 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.cpp @@ -89,11 +89,51 @@ namespace AZ::IO return m_pCache->RemoveDir(fullPath); } + ////////////////////////////////////////////////////////////////////////// int NestedArchive::RemoveAll() { return m_pCache->RemoveAll(); } + ////////////////////////////////////////////////////////////////////////// + // Helper for 'ListAllFiles' to recursively traverse the FileEntryTree and gather all the files + void EnumerateFilesRecursive(AZ::IO::Path currentPath, ZipDir::FileEntryTree* currentTree, AZStd::vector& fileList) + { + // Drill down directories first... + for (auto dirIter = currentTree->GetDirBegin(); dirIter != currentTree->GetDirEnd(); ++dirIter) + { + if (ZipDir::FileEntryTree* subTree = currentTree->GetDirEntry(dirIter); + subTree != nullptr) + { + EnumerateFilesRecursive(currentPath / currentTree->GetDirName(dirIter), subTree, fileList); + } + } + + // Then enumerate the files in current directory... + for (auto fileIter = currentTree->GetFileBegin(); fileIter != currentTree->GetFileEnd(); ++fileIter) + { + fileList.emplace_back(currentPath / currentTree->GetFileName(fileIter)); + } + } + + ////////////////////////////////////////////////////////////////////////// + // lists all files in the archive + int NestedArchive::ListAllFiles(AZStd::vector& outFileEntries) + { + AZStd::vector filesInArchive; + + ZipDir::FileEntryTree* tree = m_pCache->GetRoot(); + if (!tree) + { + return ZipDir::ZD_ERROR_UNEXPECTED; + } + + EnumerateFilesRecursive(AZ::IO::Path{ AZ::IO::PosixPathSeparator }, tree, filesInArchive); + + AZStd::swap(outFileEntries, filesInArchive); + return ZipDir::ZD_ERROR_SUCCESS; + } + ////////////////////////////////////////////////////////////////////////// // Adds a new file to the zip or update an existing one // adds a directory (creates several nested directories if needed) diff --git a/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.h b/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.h index 34bbcdc201..59722703f2 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.h +++ b/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.h @@ -39,7 +39,7 @@ namespace AZ::IO NestedArchive(IArchive* pArchive, AZStd::string_view strBindRoot, ZipDir::CachePtr pCache, uint32_t nFlags = 0); ~NestedArchive() override; - + auto GetRootFolderHandle() -> Handle override; // Adds a new file to the zip or update an existing one @@ -68,6 +68,9 @@ namespace AZ::IO // deletes all files from the archive int RemoveAll() override; + // lists all the files in the archive + int ListAllFiles(AZStd::vector& outFileEntries) override; + // finds the file; you don't have to close the returned handle Handle FindFile(AZStd::string_view szRelativePath) override; @@ -79,7 +82,6 @@ namespace AZ::IO // returns the full path to the archive file AZ::IO::PathView GetFullPath() const override; - ZipDir::Cache* GetCache(); uint32_t GetFlags() const override; bool SetFlags(uint32_t nFlagsToSet) override; @@ -87,12 +89,15 @@ namespace AZ::IO bool SetPackAccessible(bool bAccessible) override; + ZipDir::Cache* GetCache(); + protected: // returns the pointer to the relative file path to be passed // to the underlying Cache pointer. Uses the given buffer to construct the path. // returns nullptr if the file path is invalid AZ::IO::FixedMaxPathString AdjustPath(AZStd::string_view szRelativePath); + ZipDir::CachePtr m_pCache; // the binding root may be empty string - in this case, the absolute path binding won't work AZ::IO::Path m_strBindRoot; diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.cpp b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.cpp index d17dbd0837..13d5b0f723 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.cpp @@ -101,10 +101,11 @@ namespace AZ::IO::ZipDir FileEntry* operator -> () { return m_pFileEntry; } FileEntryTransactionAdd(Cache* pCache, AZStd::string_view szRelativePath) : m_pCache(pCache) + , m_szRelativePath(AZ::IO::PosixPathSeparator) , m_bCommitted(false) { // Update the cache string pool with the relative path to the file - auto pathIt = m_pCache->m_relativePathPool.emplace(AZ::IO::PathView(szRelativePath).LexicallyNormal()); + auto pathIt = m_pCache->m_relativePathPool.emplace(AZ::IO::PathView(szRelativePath, AZ::IO::PosixPathSeparator).LexicallyNormal()); m_szRelativePath = *pathIt.first; // this is the name of the directory - create it or find it m_pFileEntry = m_pCache->GetRoot()->Add(m_szRelativePath.Native()); @@ -740,6 +741,16 @@ namespace AZ::IO::ZipDir { return ZD_ERROR_CORRUPTED_DATA; } + if (pFileEntry->bCheckCRCNextRead) + { + pFileEntry->bCheckCRCNextRead = false; + uLong uCRC32 = AZ::Crc32((Bytef*)pUncompressed, nSizeUncompressed); + if (uCRC32 != pFileEntry->desc.lCRC32) + { + AZ_Warning("Archive", false, "ZD_ERROR_CRC32_CHECK: Uncompressed stream CRC32 check failed"); + return ZD_ERROR_CRC32_CHECK; + } + } } } diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.cpp b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.cpp index 5c5e93d441..d5bd4d2840 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.cpp @@ -29,7 +29,7 @@ namespace AZ::IO::ZipDir // this sets the window size of the blocks of data read from the end of the file to find the Central Directory Record // since normally there are no static constexpr size_t CDRSearchWindowSize = 0x100; - CacheFactory::CacheFactory(InitMethodEnum nInitMethod, uint32_t nFlags) + CacheFactory::CacheFactory(InitMethod nInitMethod, uint32_t nFlags) { m_nCDREndPos = 0; m_bBuildFileEntryMap = false; // we only need it for validation/debugging @@ -448,7 +448,6 @@ namespace AZ::IO::ZipDir // builds up the m_mapFileEntries bool CacheFactory::BuildFileEntryMap() { - Seek(m_CDREnd.lCDROffset); if (m_CDREnd.lCDRSize == 0) @@ -530,14 +529,6 @@ namespace AZ::IO::ZipDir { // Add this file entry. char* str = reinterpret_cast(pFileName); - for (int i = 0; i < pFile->nFileNameLength; i++) - { - str[i] = std::tolower(str[i], std::locale()); - if (str[i] == AZ_WRONG_FILESYSTEM_SEPARATOR) - { - str[i] = AZ_CORRECT_FILESYSTEM_SEPARATOR; - } - } str[pFile->nFileNameLength] = 0; // Not standard!, may overwrite signature of the next memory record data in zip. AddFileEntry(str, pFile, extra); } @@ -574,11 +565,7 @@ namespace AZ::IO::ZipDir FileEntryBase fileEntry(*pFileHeader, extra); - // when using encrypted headers we should always initialize data offsets from CDR - if ((m_encryptedHeaders != ZipFile::HEADERS_NOT_ENCRYPTED || m_nInitMethod >= ZD_INIT_FULL) && pFileHeader->desc.lSizeCompressed) - { - InitDataOffset(fileEntry, pFileHeader); - } + InitDataOffset(fileEntry, pFileHeader); if (m_bBuildFileEntryMap) { @@ -606,142 +593,81 @@ namespace AZ::IO::ZipDir { Seek(pFileHeader->lLocalHeaderOffset); - // read the local file header and the name (for validation) into the buffer - AZStd::vectorpBuffer; - uint32_t nBufferLength = sizeof(ZipFile::LocalFileHeader) + pFileHeader->nFileNameLength; - pBuffer.resize(nBufferLength); - Read(&pBuffer[0], nBufferLength); + // Read only the LocalFileHeader w/ no additional bytes ('name' or 'extra' fields) + AZStd::vector buffer; + uint32_t bufferLen = sizeof(ZipFile::LocalFileHeader); + buffer.resize_no_construct(bufferLen); + Read(buffer.data(), bufferLen); - // validate the local file header (compare with the CDR file header - they should contain basically the same information) - const auto* pLocalFileHeader = reinterpret_cast(&pBuffer[0]); - if (pFileHeader->desc != pLocalFileHeader->desc - || pFileHeader->nMethod != pLocalFileHeader->nMethod - || pFileHeader->nFileNameLength != pLocalFileHeader->nFileNameLength - // for a tough validation, we can compare the timestamps of the local and central directory entries - // but we won't do that for backward compatibility with ZipDir - //|| pFileHeader->nLastModDate != pLocalFileHeader->nLastModDate - //|| pFileHeader->nLastModTime != pLocalFileHeader->nLastModTime - ) + const auto* localFileHeader = reinterpret_cast(buffer.data()); + + // set the correct file data offset... + fileEntry.nFileDataOffset = pFileHeader->lLocalHeaderOffset + sizeof(ZipFile::LocalFileHeader) + + localFileHeader->nFileNameLength + localFileHeader->nExtraFieldLength; + + fileEntry.nEOFOffset = fileEntry.nFileDataOffset + fileEntry.desc.lSizeCompressed; + + if (m_nInitMethod != ZipDir::InitMethod::Default) { - AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED:" - " The local file header descriptor doesn't match the basic parameters declared in the global file header in the file." - " The archive content is misconsistent and may be damaged. Please try to repair the archive"); - return; + if (m_nInitMethod == ZipDir::InitMethod::FullValidation) + { + // Mark the FileEntry to check CRC when the next read occurs + fileEntry.bCheckCRCNextRead = true; + } + + // Timestamps + if (pFileHeader->nLastModDate != localFileHeader->nLastModDate + || pFileHeader->nLastModTime != localFileHeader->nLastModTime) + { + AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED: (%s)\n" + " The local file header's modification timestamps don't match that of the global file header in the archive." + " The archive timestamps are inconsistent and may be damaged. Check the archive file.", m_szFilename.c_str()); + // don't return here, it may be ok. + } + + // Validate data + if (pFileHeader->desc != localFileHeader->desc // this checks CRCs and compressed/uncompressed sizes + || pFileHeader->nMethod != localFileHeader->nMethod + || pFileHeader->nFileNameLength != localFileHeader->nFileNameLength) + { + AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED: (%s)\n" + " The local file header descriptor doesn't match basic parameters declared in the global file header in the file." + " The archive content is inconsistent and may be damaged. Please try to repair the archive.", m_szFilename.c_str()); + // return here because further checks aren't worse than this. + return; + } + + // Read extra data + uint32_t extraDataLen = localFileHeader->nFileNameLength + localFileHeader->nExtraFieldLength; + buffer.resize_no_construct(buffer.size() + extraDataLen); + Read(buffer.data() + buffer.size(), extraDataLen); + + // Compare local file name with the CDR file name, they should match + AZStd::string_view zipFileName{ buffer.data() + sizeof(ZipFile::LocalFileHeader), localFileHeader->nFileNameLength }; + AZStd::string_view cdrFileName{ reinterpret_cast(pFileHeader + 1), pFileHeader->nFileNameLength }; + if (zipFileName != cdrFileName) + { + AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED: (%s)\n" + " The file name in the local file header doesn't match the name in the global file header." + " The archive content is inconsisten with the directory. Please check the archive.", m_szFilename.c_str()); + } + + // CDR and local "extra field" lengths may be different, should we compare them if they are equal? + + // make sure it's the same file and the fileEntry structure is properly initialized + AZ_Assert(fileEntry.nFileHeaderOffset == pFileHeader->lLocalHeaderOffset, + "The file entry header offset doesn't match the file header local offst (%s)", m_szFilename.c_str()); + + if (fileEntry.nFileDataOffset >= m_nCDREndPos) + { + AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED: (%s)\n" + " The global file header declares the file which crosses the boundaries of the archive." + " The archive is either corrupted or truncated, please try to repair it", m_szFilename.c_str()); + } + + // End Validation } - - // now compare the local file name with the one recorded in CDR: they must match. - auto CompareNoCase = [](const char lhs, const char rhs) { return std::tolower(lhs, std::locale()) == std::tolower(rhs, std::locale()); }; - auto zipFileDataBegin = pBuffer.begin() + sizeof(ZipFile::LocalFileHeader); - auto zipFileDataEnd = zipFileDataBegin + pFileHeader->nFileNameLength; - if (!AZStd::equal(zipFileDataBegin, zipFileDataEnd, reinterpret_cast(pFileHeader + 1), CompareNoCase)) - { - // either file name, or the extra field do not match - AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED:" - " The local file header contains file name which does not match the file name of the global file header." - " The archive content is misconsistent with its directory. Please repair the archive"); - return; - } - - fileEntry.nFileDataOffset = pFileHeader->lLocalHeaderOffset + sizeof(ZipFile::LocalFileHeader) + pLocalFileHeader->nFileNameLength + pLocalFileHeader->nExtraFieldLength; } - - // make sure it's the same file and the fileEntry structure is properly initialized - AZ_Assert(fileEntry.nFileHeaderOffset == pFileHeader->lLocalHeaderOffset, "The file entry header offset doesn't match the file header local offst"); - - fileEntry.nEOFOffset = fileEntry.nFileDataOffset + fileEntry.desc.lSizeCompressed; - - if (fileEntry.nFileDataOffset >= m_nCDREndPos) - { - AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED:" - " The global file header declares the file which crosses the boundaries of the archive." - " The archive is either corrupted or truncated, please try to repair it"); - return; - } - - if (m_nInitMethod >= ZD_INIT_VALIDATE) - { - Validate(fileEntry); - } - } - - ////////////////////////////////////////////////////////////////////////// - // reads the file pointed by the given header and entry (they must be coherent) - // and decompresses it; then calculates and validates its CRC32 - void CacheFactory::Validate(const FileEntryBase& fileEntry) - { - AZStd::vector pBuffer; - // validate the file contents - // allocate memory for both the compressed data and uncompressed data - pBuffer.resize(fileEntry.desc.lSizeCompressed + fileEntry.desc.lSizeUncompressed); - char* pUncompressed = &pBuffer[fileEntry.desc.lSizeCompressed]; - char* pCompressed = &pBuffer[0]; - - AZ_Assert(fileEntry.nFileDataOffset != FileEntry::INVALID_DATA_OFFSET, "File entry has invalid data offset of %" PRIx32, FileEntry::INVALID_DATA_OFFSET); - Seek(fileEntry.nFileDataOffset); - - Read(pCompressed, fileEntry.desc.lSizeCompressed); - - size_t nDestSize = fileEntry.desc.lSizeUncompressed; - int nError = Z_OK; - if (fileEntry.nMethod) - { - nError = ZipRawUncompress(pUncompressed, &nDestSize, pCompressed, fileEntry.desc.lSizeCompressed); - } - else - { - AZ_Assert(fileEntry.desc.lSizeCompressed == fileEntry.desc.lSizeUncompressed, "Uncompressed file does not have the same commpressed %u and uncompressed file sizes %u", - fileEntry.desc.lSizeCompressed, fileEntry.desc.lSizeUncompressed); - memcpy(pUncompressed, pCompressed, fileEntry.desc.lSizeUncompressed); - } - switch (nError) - { - case Z_OK: - break; - case Z_MEM_ERROR: - AZ_Warning("Archive", false, "ZD_ERROR_ZLIB_NO_MEMORY: ZLib reported out-of-memory error"); - return; - case Z_BUF_ERROR: - AZ_Warning("Archive", false, "ZD_ERROR_ZLIB_CORRUPTED_DATA: ZLib reported compressed stream buffer error"); - return; - case Z_DATA_ERROR: - AZ_Warning("Archive", false, "ZD_ERROR_ZLIB_CORRUPTED_DATA: ZLib reported compressed stream data error"); - return; - default: - AZ_Warning("Archive", false, "ZD_ERROR_ZLIB_FAILED: ZLib reported an unexpected unknown error"); - return; - } - - if (nDestSize != fileEntry.desc.lSizeUncompressed) - { - AZ_Warning("Archive", false, "ZD_ERROR_CORRUPTED_DATA: Uncompressed stream doesn't match the size of uncompressed file stored in the archive file headers"); - return; - } - - uLong uCRC32 = AZ::Crc32((Bytef*)pUncompressed, nDestSize); - if (uCRC32 != fileEntry.desc.lCRC32) - { - AZ_Warning("Archive", false, "ZD_ERROR_CRC32_CHECK: Uncompressed stream CRC32 check failed"); - return; - } - } - - - ////////////////////////////////////////////////////////////////////////// - // extracts the file path from the file header with subsequent information - // may, or may not, put all letters to lower-case (depending on whether the system is to be case-sensitive or not) - // it's the responsibility of the caller to ensure that the file name is in readable valid memory - char* CacheFactory::GetFilePath(const char* pFileName, uint16_t nFileNameLength) - { - static char strResult[AZ_MAX_PATH_LEN]; - AZ_Assert(nFileNameLength < AZ_MAX_PATH_LEN, "Only filenames shorter than %zu can be copied from filename parameter", AZ_MAX_PATH_LEN); - memcpy(strResult, pFileName, nFileNameLength); - strResult[nFileNameLength] = 0; - for (int i = 0; i < nFileNameLength; i++) - { - strResult[i] = std::tolower(strResult[i], std::locale{}); - } - - return strResult; } // seeks in the file relative to the starting position diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.h b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.h index c31d4d7dfd..1612829f13 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.h +++ b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.h @@ -39,7 +39,7 @@ namespace AZ::IO::ZipDir // initializes the internal structures // nFlags can have FLAGS_READ_ONLY flag, in this case the object will be opened only for reading - CacheFactory(InitMethodEnum nInitMethod, uint32_t nFlags = 0); + CacheFactory(InitMethod nInitMethod, uint32_t nFlags = 0); ~CacheFactory(); // the new function creates a new cache @@ -66,28 +66,6 @@ namespace AZ::IO::ZipDir // This function can actually modify strFilePath variable, make sure you use a copy of the real path. void AddFileEntry(char* strFilePath, const ZipFile::CDRFileHeader* pFileHeader, const SExtraZipFileData& extra);// throw (ErrorEnum); - // extracts the file path from the file header with subsequent information - // may, or may not, put all letters to lower-case (depending on whether the system is to be case-sensitive or not) - // it's the responsibility of the caller to ensure that the file name is in readable valid memory - char* GetFilePath(const ZipFile::CDRFileHeader* pFileHeader) - { - return GetFilePath((const char*)(pFileHeader + 1), pFileHeader->nFileNameLength); - } - // extracts the file path from the file header with subsequent information - // may, or may not, put all letters to lower-case (depending on whether the system is to be case-sensitive or not) - // it's the responsibility of the caller to ensure that the file name is in readable valid memory - char* GetFilePath(const ZipFile::LocalFileHeader* pFileHeader) - { - return GetFilePath((const char*)(pFileHeader + 1), pFileHeader->nFileNameLength); - } - // extracts the file path from the file header with subsequent information - // may, or may not, put all letters to lower-case (depending on whether the system is to be case-sensitive or not) - // it's the responsibility of the caller to ensure that the file name is in readable valid memory - char* GetFilePath(const char* pFileName, uint16_t nFileNameLength); - - // validates (if the init method has the corresponding value) the given file/header - void Validate(const FileEntryBase& fileEntry); - // initializes the actual data offset in the file in the fileEntry structure // searches to the local file header, reads it and calculates the actual offset in the file void InitDataOffset(FileEntryBase& fileEntry, const ZipFile::CDRFileHeader* pFileHeader); @@ -104,7 +82,7 @@ namespace AZ::IO::ZipDir AZStd::string m_szFilename; CZipFile m_fileExt; - InitMethodEnum m_nInitMethod; + InitMethod m_nInitMethod; uint32_t m_nFlags; ZipFile::CDREnd m_CDREnd; @@ -129,7 +107,7 @@ namespace AZ::IO::ZipDir ZipFile::CryCustomEncryptionHeader m_headerEncryption; ZipFile::CrySignedCDRHeader m_headerSignature; ZipFile::CryCustomExtendedHeader m_headerExtended; - }; + } diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirList.cpp b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirList.cpp index 729f394b9d..ab9c356d7f 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirList.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirList.cpp @@ -68,14 +68,14 @@ namespace AZ::IO::ZipDir { for (FileEntryTree::SubdirMap::iterator it = pTree->GetDirBegin(); it != pTree->GetDirEnd(); ++it) { - AddAllFiles(it->second.get(), (AZ::IO::Path(strRoot) / it->first).Native()); + AddAllFiles(it->second.get(), (AZ::IO::Path(strRoot, AZ::IO::PosixPathSeparator) / it->first).Native()); } for (FileEntryTree::FileMap::iterator it = pTree->GetFileBegin(); it != pTree->GetFileEnd(); ++it) { FileRecord rec; rec.pFileEntryBase = pTree->GetFileEntry(it); - rec.strPath = (AZ::IO::Path(strRoot) / it->first).Native(); + rec.strPath = (AZ::IO::Path(strRoot, AZ::IO::PosixPathSeparator) / it->first).Native(); push_back(rec); } } diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirStructures.h b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirStructures.h index 9295a7dd95..c890d498e4 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirStructures.h +++ b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirStructures.h @@ -119,19 +119,28 @@ namespace AZ::IO::ZipDir const char* m_szDescription; }; +#if defined(_RELEASE) + inline static constexpr bool IsReleaseConfig{ true }; +#else + inline static constexpr bool IsReleaseConfig{}; +#endif // _RELEASE + // possible initialization methods - enum InitMethodEnum + enum class InitMethod { - // initialize as fast as possible, with minimal validation - ZD_INIT_FAST, - // after initialization, scan through all file headers, precache the actual file data offset values and validate the headers - ZD_INIT_FULL, - // scan all file headers and try to decompress the data, searching for corrupted files - ZD_INIT_VALIDATE_IN_MEMORY, - // store archive in memory - ZD_INIT_VALIDATE, - // maximum level of validation, checks for integrity of the archive - ZD_INIT_VALIDATE_MAX = ZD_INIT_VALIDATE + // initializes without any sort of extra validation steps + Default, + + // initializes with extra validation steps + // not available in RELEASE + // will check CDR and local headers data match + ValidateHeaders, + + // initializes with extra validation steps + // not available in RELEASE + // will check CDR and local headers data match + // will check file data CRC matches (when file is read) + FullValidation, }; // Uncompresses raw (without wrapping) data that is compressed with method 8 (deflated) in the Zip file @@ -184,7 +193,11 @@ namespace AZ::IO::ZipDir // the offset to the start of the next file's header - this // can be used to calculate the available space in zip file uint32_t nEOFOffset{}; + + // whether to check the CRC upon the next data read + bool bCheckCRCNextRead{}; }; + // this is the record about the file in the Zip file. struct FileEntry : FileEntryBase diff --git a/Code/Framework/AzFramework/AzFramework/Network/AssetProcessorConnection.cpp b/Code/Framework/AzFramework/AzFramework/Network/AssetProcessorConnection.cpp index 2e1cde443c..74b92a5681 100644 --- a/Code/Framework/AzFramework/AzFramework/Network/AssetProcessorConnection.cpp +++ b/Code/Framework/AzFramework/AzFramework/Network/AssetProcessorConnection.cpp @@ -593,7 +593,7 @@ namespace AzFramework DebugMessage("StartThread: Starting %s", thread.m_desc.m_name); thread.m_join = false; - thread.m_thread = AZStd::thread(thread.m_main, &thread.m_desc); + thread.m_thread = AZStd::thread(thread.m_desc, thread.m_main); } void AssetProcessorConnection::JoinThread(ThreadState& thread, AZStd::condition_variable* wakeUpCondition /* = nullptr */) diff --git a/Code/Framework/AzFramework/AzFramework/TargetManagement/TargetManagementComponent.cpp b/Code/Framework/AzFramework/AzFramework/TargetManagement/TargetManagementComponent.cpp index 1c26cbc744..8e6bacda2b 100644 --- a/Code/Framework/AzFramework/AzFramework/TargetManagement/TargetManagementComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/TargetManagement/TargetManagementComponent.cpp @@ -319,7 +319,7 @@ namespace AzFramework AZStd::thread_desc td; td.m_name = "TargetManager Thread"; td.m_cpuId = AFFINITY_MASK_USERTHREADS; - m_threadHandle = AZStd::thread(AZStd::bind(&TargetManagementComponent::TickThread, this), &td); + m_threadHandle = AZStd::thread(td, AZStd::bind(&TargetManagementComponent::TickThread, this)); } void TargetManagementComponent::Deactivate() diff --git a/Code/Framework/AzNetworking/AzNetworking/Utilities/TimedThread.cpp b/Code/Framework/AzNetworking/AzNetworking/Utilities/TimedThread.cpp index c85d15ae45..565b37202a 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Utilities/TimedThread.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/Utilities/TimedThread.cpp @@ -26,27 +26,29 @@ namespace AzNetworking { m_running = true; m_joinable = true; - m_thread = AZStd::thread([this]() - { - OnStart(); - while (m_running) + m_thread = AZStd::thread( + m_threadDesc, + [this]() { - const AZ::TimeMs startTimeMs = AZ::GetElapsedTimeMs(); - OnUpdate(m_updateRate); - const AZ::TimeMs updateTimeMs = AZ::GetElapsedTimeMs() - startTimeMs; + OnStart(); + while (m_running) + { + const AZ::TimeMs startTimeMs = AZ::GetElapsedTimeMs(); + OnUpdate(m_updateRate); + const AZ::TimeMs updateTimeMs = AZ::GetElapsedTimeMs() - startTimeMs; - if (m_updateRate > updateTimeMs) - { - AZStd::chrono::milliseconds sleepTimeMs(static_cast(m_updateRate - updateTimeMs)); - AZStd::this_thread::sleep_for(sleepTimeMs); + if (m_updateRate > updateTimeMs) + { + AZStd::chrono::milliseconds sleepTimeMs(static_cast(m_updateRate - updateTimeMs)); + AZStd::this_thread::sleep_for(sleepTimeMs); + } + else if (m_updateRate < updateTimeMs) + { + AZLOG(NET_TimedThread, "TimedThread bled %d ms", aznumeric_cast(updateTimeMs - m_updateRate)); + } } - else if (m_updateRate < updateTimeMs) - { - AZLOG(NET_TimedThread, "TimedThread bled %d ms", aznumeric_cast(updateTimeMs - m_updateRate)); - } - } - OnStop(); - }, &m_threadDesc); + OnStop(); + }); } void TimedThread::Stop() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveAPI.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveAPI.h index fa8c2c14ff..11c4c85722 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveAPI.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveAPI.h @@ -12,95 +12,84 @@ #include #include #include +#include namespace AzToolsFramework { - // use bind if you need additional context. - // Parameters: - // bool - If the archive command was successful or not. - typedef AZStd::function ArchiveResponseCallback; - // bool - If the archive command was successful or not. - // AZStd::string - The console output from the command. - typedef AZStd::function ArchiveResponseOutputCallback; - - //! ArchiveCommands //! This bus handles messages relating to archive commands //! archive commands are ASYNCHRONOUS //! archive formats officially supported are .zip - //! do not block the main thread waiting for a response, it is not okay - //! you will not get a message delivered unless you tick the tickbus anyway! class ArchiveCommands : public AZ::EBusTraits { public: - - using Bus = AZ::EBus; - + // EBus Traits static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; typedef AZStd::recursive_mutex MutexType; static const bool LocklessDispatch = true; - virtual ~ArchiveCommands() {} - //! Start an async task to extract an archive to the target directory - //! taskHandles are used to cancel a task at some point in the future and are provided by the caller per task. - //! Multiple tasks can be associated with the same handle - virtual void ExtractArchive(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseCallback& respCallback) = 0; - virtual void ExtractArchiveOutput(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0; - // Maintaining backwards API compatibility - ExtractArchiveBlocking below passes in extractWithRoot as an option - virtual void ExtractArchiveWithoutRoot(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0; + virtual ~ArchiveCommands() = default; - //! Start a sync task to extract an archive to the target directory - //! If you do not want to extract the root folder then set extractWithRootDirectory to false. - virtual bool ExtractArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool extractWithRootDirectory) = 0; + //! Create an archive of the target directory (all files and subdirectories) + //! @param archivePath The path of the archive to create + //! @dirToArchive The directory to be added to the archive + //! @return Future (bool) which can obtain the success value of the operation + [[nodiscard]] virtual std::future CreateArchive( + const AZStd::string& archivePath, + const AZStd::string& dirToArchive) = 0; - //! Extract a single file asynchronously from the archive to the destination. - //! Uses cwd if destinationPath empty. overWrite = true for overwrite existing files, false for skipExisting - //! taskHandles are used to cancel a task at some point in the future and are provided by the caller per task. - //! Multiple tasks can be associated with the same handle - virtual void ExtractFile(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0; + //! Extract an archive to the target directory + //! @param archivePath The path of the archive to extract + //! @param destinationPath The directory where files will be extracted to + //! @return Future (bool) which can obtain the success value of the operation + [[nodiscard]] virtual std::future ExtractArchive( + const AZStd::string& archivePath, + const AZStd::string& destinationPath) = 0; - //! Extract a single file from the archive to the destination and block until finished. - //! Uses cwd if destinationPath empty. overWrite = true for overwrite existing files, false for skipExisting - virtual bool ExtractFileBlocking(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite) = 0; + //! Extract a single file from the archive to the destination + //! Destination path should not be empty + //! @param archivePath The path of the archive to extract from + //! @param fileInArchive A path to a file, relative to root of archive + //! @param destinationPath The directory where file will be extracted to + //! @return Future (bool) which can obtain the success value of the operation + [[nodiscard]] virtual std::future ExtractFile( + const AZStd::string& archivePath, + const AZStd::string& fileInArchive, + const AZStd::string& destinationPath) = 0; - //! Start an async task to create an archive of the target directory (recursively) - //! taskHandles are used to cancel a task at some point in the future and are provided by the caller per task. - //! Multiple tasks can be associated with the same handle. - virtual void CreateArchive(const AZStd::string& archivePath, const AZStd::string& dirToArchive, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0; + //! Retrieve the list of files contained in an archive (all files and subdirectories) + //! @param archivePath The path of the archive to list + //! @param outFileEntries An out parameter that will contain the file paths found + //! @return True if successful, false otherwise + virtual bool ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector& outFileEntries) = 0; - //! Start a sync task to create an archive of the target directory (recursively) - virtual bool CreateArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& dirToArchive) = 0; - - //! Start an async task to retrieve the list of files and their relative paths within an archive (recursively) - //! taskHandles are used to cancel a task at some point in the future and are provided by the caller per task. - //! Multiple tasks can be associated with the same handle. - virtual void ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector& fileEntries, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0; + //! Add a file to an archive + //! The archive might not exist yet + //! The file path relative to the working directory will be replicated in the archive + //! @param archivePath The path of the archive to add to + //! @param workingDirectory A directory that will be the starting path of the file to be added + //! @param fileToAdd A path to the file relative to the working directory + //! @return Future (bool) which can obtain the success value of the operation + [[nodiscard]] virtual std::future AddFileToArchive( + const AZStd::string& archivePath, + const AZStd::string& workingDirectory, + const AZStd::string& fileToAdd) = 0; - //! Start a sync task to retrieve the list of files and their relative paths within an archive (recursively) - virtual bool ListFilesInArchiveBlocking(const AZStd::string& archivePath, AZStd::vector& fileEntries) = 0; - - //! Start an async task to add a file to a preexisting archive. - //! fileToAdd must be a relative path to the file from the working directory. The path to the file from the root of the archive will be the same as the relative path to the file on disk. - //! taskHandles are used to cancel a task at some point in the future and are provided by the caller per task. - //! Multiple tasks can be associated with the same handle. - virtual void AddFileToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& fileToAdd, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0; - - //! Start a sync task to add a file to a preexisting archive. - //! fileToAdd must be a relative path to the file from the working directory. The path to the file from the root of the archive will be the same as the relative path to the file on disk. - virtual bool AddFileToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& fileToAdd) = 0; - - //! Start an async task to add files to a archive. - //! File paths inside the list file must either be a relative path from the working directory or an absolute path. - virtual void AddFilesToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0; - - //! Start a sync task to add files to an archive. - //! File paths inside the list file must either be a relative path from the working directory or an absolute path. - virtual bool AddFilesToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath) = 0; - - //! Cancels tasks associtated with the given handle. Blocks until all tasks are cancelled. - virtual void CancelTasks(AZ::Uuid taskHandle) = 0; + //! Add files to an archive provided from a file listing + //! The archive might not exist yet + //! File paths in the file list should be relative to root of the archive + //! @param archivePath The path of the archive to add to + //! @param workingDirectory A directory that will be the starting path of the list of files to add + //! @param listFilePath Full path to a text file that contains the list of files to add + //! @return Future (bool) which can obtain the success value of the operation + [[nodiscard]] virtual std::future AddFilesToArchive( + const AZStd::string& archivePath, + const AZStd::string& workingDirectory, + const AZStd::string& listFilePath) = 0; }; + using ArchiveCommandsBus = AZ::EBus; + }; // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.cpp index 5004108132..8e07794c33 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.cpp @@ -12,118 +12,98 @@ #include #include -#include - +#include +#include #include #include #include + namespace AzToolsFramework { - // Forward declare platform specific functions - namespace Platform + constexpr const char s_traceName[] = "ArchiveComponent"; + constexpr AZ::u32 s_compressionMethod = AZ::IO::INestedArchive::METHOD_DEFLATE; + constexpr AZ::s32 s_compressionLevel = AZ::IO::INestedArchive::LEVEL_NORMAL; + constexpr CompressionCodec::Codec s_compressionCodec = CompressionCodec::Codec::ZLIB; + + namespace ArchiveUtils { - AZStd::string GetZipExePath(); - AZStd::string GetUnzipExePath(); - - AZStd::string GetCreateArchiveCommand(const AZStd::string& archivePath, const AZStd::string& dirToArchive); - AZStd::string GetExtractArchiveCommand(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool includeRoot); - AZStd::string GetAddFileToArchiveCommand(const AZStd::string& archivePath, const AZStd::string& file); - AZStd::string GetAddFilesToArchiveCommand(const AZStd::string& archivePath, const AZStd::string& listFilePath); - AZStd::string GetExtractFileCommand(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite); - AZStd::string GetListFilesInArchiveCommand(const AZStd::string& archivePath); - void ParseConsoleOutputFromListFilesInArchive(const AZStd::string& consoleOutput, AZStd::vector& fileEntries); - } - - const char s_traceName[] = "ArchiveComponent"; - const unsigned int g_sleepDuration = 1; - - // Echoes all results of stdout and stderr to console and never blocks - class ConsoleEchoCommunicator - { - public: - ConsoleEchoCommunicator(AzFramework::ProcessCommunicator* communicator) - : m_communicator(communicator) + // Read a file's contents into a provided buffer. + // Does not add a zero byte at the end of the buffer. + // returns true if read was successful, false otherwise. + bool ReadFile(const AZ::IO::Path& filePath, AZ::IO::OpenMode openMode, AZStd::vector& outBuffer) { - } - - ~ConsoleEchoCommunicator() - { - } - - // Call this periodically to drain the buffers - void Pump() - { - if (m_communicator->IsValid()) + auto fileIO = AZ::IO::FileIOBase::GetDirectInstance(); + if (!fileIO) { - AZ::u32 readBufferSize = 0; - AZStd::string readBuffer; - // Don't call readOutput unless there is output or else it will block... - readBufferSize = m_communicator->PeekOutput(); - if (readBufferSize) - { - readBuffer.resize_no_construct(readBufferSize + 1); - readBuffer[readBufferSize] = '\0'; - m_communicator->ReadOutput(readBuffer.data(), readBufferSize); - EchoBuffer(readBuffer); - } - readBufferSize = m_communicator->PeekError(); - if (readBufferSize) - { - readBuffer.resize_no_construct(readBufferSize + 1); - readBuffer[readBufferSize] = '\0'; - m_communicator->ReadError(readBuffer.data(), readBufferSize); - EchoBuffer(readBuffer); - } + return false; } - } - private: - void EchoBuffer(const AZStd::string& buffer) - { - size_t startIndex = 0; - size_t endIndex = 0; - const size_t bufferSize = buffer.size(); - for (size_t i = 0; i < bufferSize; ++i) + bool success = false; + AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle; + if (fileIO->Open(filePath.c_str(), openMode, fileHandle)) { - if (buffer[i] == '\n' || buffer[i] == '\0') + AZ::u64 fileSize = 0; + if (fileIO->Size(fileHandle, fileSize) && fileSize != 0) { - endIndex = i; - bool isEmptyMessage = (endIndex - startIndex == 1) && (buffer[startIndex] == '\r'); - if (!isEmptyMessage) + outBuffer.resize_no_construct(fileSize); + + AZ::u64 bytesRead = 0; + if (fileIO->Read(fileHandle, outBuffer.data(), fileSize, true, &bytesRead)) { - AZ_Printf(s_traceName, "%s", buffer.substr(startIndex, endIndex - startIndex).c_str()); + success = (fileSize == bytesRead); } - startIndex = endIndex + 1; } + + fileIO->Close(fileHandle); + } + + return success; + } + + // Reads a text file that contains a list of file paths. + // Tokenize the file by lines. + // Calls the lineVisitor function for each line of the file. + void ProcessFileList(const AZ::IO::Path& filePath, AZStd::function lineVisitor) + { + AZStd::vector fileBuffer; + if (ReadFile(filePath, AZ::IO::OpenMode::ModeText | AZ::IO::OpenMode::ModeRead, fileBuffer)) + { + AZ::StringFunc::TokenizeVisitor(AZStd::string_view{ fileBuffer.data(), fileBuffer.size() }, lineVisitor, "\n"); } } - AzFramework::ProcessCommunicator* m_communicator = nullptr; - }; + } // namespace ArchiveUtils void ArchiveComponent::Activate() { - m_zipExePath = Platform::GetZipExePath(); - m_unzipExePath = Platform::GetUnzipExePath(); + m_fileIO = AZ::IO::FileIOBase::GetDirectInstance(); + if (m_fileIO == nullptr) + { + AZ_Error(s_traceName, false, "Failed to create a LocalFileIO instance!"); + } - ArchiveCommands::Bus::Handler::BusConnect(); + m_archive = AZ::Interface::Get(); + if (m_archive == nullptr) + { + AZ_Error(s_traceName, false, "Failed to get IArchive interface!"); + } + + ArchiveCommandsBus::Handler::BusConnect(); } void ArchiveComponent::Deactivate() { - ArchiveCommands::Bus::Handler::BusDisconnect(); + ArchiveCommandsBus::Handler::BusDisconnect(); - AZStd::unique_lock lock(m_threadControlMutex); - for (auto pair : m_threadInfoMap) + m_fileIO = nullptr; + m_archive = nullptr; + + for (AZStd::thread& t : m_threads) { - ThreadInfo& info = pair.second; - info.shouldStop = true; - m_cv.wait(lock, [&info]() { - return info.threads.size() == 0; - }); + t.join(); } - m_threadInfoMap.clear(); + m_threads = {}; } void ArchiveComponent::Reflect(AZ::ReflectContext * context) @@ -132,7 +112,7 @@ namespace AzToolsFramework { serializeContext->Class() ->Version(2) - ->Attribute(AZ::Edit::Attributes::SystemComponentTags, AZStd::vector({ AZ_CRC("AssetBuilder", 0xc739c7d7) })) + ->Attribute(AZ::Edit::Attributes::SystemComponentTags, AZStd::vector({ AZ_CRC_CE("AssetBuilder") })) ; if (AZ::EditContext* editContext = serializeContext->GetEditContext()) @@ -141,320 +121,480 @@ namespace AzToolsFramework "Archive", "Handles creation and extraction of zip archives.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "Editor") - ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b)) + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System")) ; } } } - void ArchiveComponent::CreateArchive(const AZStd::string& archivePath, const AZStd::string& dirToArchive, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) + std::future ArchiveComponent::CreateArchive( + const AZStd::string& archivePath, + const AZStd::string& dirToArchive) { - AZStd::string commandLineArgs = AZStd::string::format(R"(a -tzip -mx=1 "%s" -r "%s\*")", archivePath.c_str(), dirToArchive.c_str()); - LaunchZipExe(m_zipExePath, commandLineArgs, respCallback, taskHandle); - } - - bool ArchiveComponent::CreateArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& dirToArchive) - { - bool success = false; - auto createArchiveCallback = [&success](bool result, AZStd::string consoleOutput) { - success = result; - }; - - AZStd::string commandLineArgs = Platform::GetCreateArchiveCommand(archivePath, dirToArchive); - - if (commandLineArgs.empty()) + if (!CheckParamsForCreate(archivePath, dirToArchive)) { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return false; + std::promise p; + p.set_value(false); + return p.get_future(); } - LaunchZipExe(m_zipExePath, commandLineArgs, createArchiveCallback, AZ::Uuid::CreateNull(), dirToArchive, false); - return success; - } - - void ArchiveComponent::ExtractArchive(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseCallback& respCallback) - { - ArchiveResponseOutputCallback responseHandler = [respCallback](bool result, AZStd::string /*outputStr*/) { respCallback(result); }; - ExtractArchiveOutput(archivePath, destinationPath, taskHandle, responseHandler); - } - - void ArchiveComponent::ExtractArchiveOutput(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) - { - AZStd::string commandLineArgs = Platform::GetExtractArchiveCommand(archivePath, destinationPath, true); - - if (commandLineArgs.empty()) + auto FnCreateArchive = [this, archivePath, dirToArchive](std::promise&& p) -> void { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return; - } - - LaunchZipExe(m_unzipExePath, commandLineArgs, respCallback, taskHandle); - } - - void ArchiveComponent::ExtractArchiveWithoutRoot(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) - { - AZStd::string commandLineArgs = Platform::GetExtractArchiveCommand(archivePath, destinationPath, false); - - if (commandLineArgs.empty()) - { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return; - } - - LaunchZipExe(m_unzipExePath, commandLineArgs, respCallback, taskHandle); - } - - void ArchiveComponent::ExtractFile(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) - { - AZStd::string commandLineArgs = AzToolsFramework::Platform::GetExtractFileCommand(archivePath, fileInArchive, destinationPath, overWrite); - if (commandLineArgs.empty()) - { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return; - } - LaunchZipExe(m_unzipExePath, commandLineArgs, respCallback, taskHandle); - } - - bool ArchiveComponent::ExtractFileBlocking(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite) - { - AZStd::string commandLineArgs = AzToolsFramework::Platform::GetExtractFileCommand(archivePath, fileInArchive, destinationPath, overWrite); - if (commandLineArgs.empty()) - { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return false; - } - - bool success = false; - auto createArchiveCallback = [&success](bool result, AZStd::string consoleOutput) { - success = result; - }; - LaunchZipExe(m_unzipExePath, commandLineArgs, createArchiveCallback); - return success; - } - - void ArchiveComponent::ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector& fileEntries, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) - { - AZStd::string commandLineArgs = Platform::GetListFilesInArchiveCommand(archivePath); - - auto parseOutput = [respCallback, &fileEntries](bool exitCode, AZStd::string consoleOutput) - { - Platform::ParseConsoleOutputFromListFilesInArchive(consoleOutput, fileEntries); - AZ::TickBus::QueueFunction(respCallback, exitCode, AZStd::move(consoleOutput)); - }; - LaunchZipExe(m_unzipExePath, commandLineArgs, parseOutput, taskHandle, "", true); - } - - bool ArchiveComponent::ListFilesInArchiveBlocking(const AZStd::string& archivePath, AZStd::vector& fileEntries) - { - AZStd::string listOutput; - AZStd::string commandLineArgs = Platform::GetListFilesInArchiveCommand(archivePath.c_str()); - bool success = false; - - auto parseOutput = [&success, &fileEntries](bool result, AZStd::string consoleOutput) - { - Platform::ParseConsoleOutputFromListFilesInArchive(consoleOutput, fileEntries); - success = result; - }; - LaunchZipExe(m_unzipExePath, commandLineArgs, parseOutput, AZ::Uuid::CreateNull(), "", true); - return success; - } - - void ArchiveComponent::AddFileToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& fileToAdd, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) - { - AZStd::string commandLineArgs = Platform::GetAddFileToArchiveCommand(archivePath, fileToAdd); - if (commandLineArgs.empty()) - { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return; - } - - LaunchZipExe(m_zipExePath, commandLineArgs, respCallback, taskHandle, workingDirectory); - } - - bool ArchiveComponent::AddFileToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& fileToAdd) - { - AZStd::string commandLineArgs = Platform::GetAddFileToArchiveCommand(archivePath, fileToAdd); - if (commandLineArgs.empty()) - { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return false; - } - bool success = false; - auto addFileToArchiveCallback = [&success](bool result, AZStd::string consoleOutput) { - success = result; - }; - - LaunchZipExe(m_zipExePath, commandLineArgs, addFileToArchiveCallback, AZ::Uuid::CreateNull(), workingDirectory); - return success; - } - - bool ArchiveComponent::AddFilesToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath) - { - bool success = false; - - auto addFileToArchiveCallback = [&success](bool result, AZStd::string consoleOutput) { - success = result; - }; - - AZStd::string commandLineArgs = Platform::GetAddFilesToArchiveCommand(archivePath.c_str(), listFilePath.c_str()); - - if (commandLineArgs.empty()) - { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return false; - } - LaunchZipExe(m_zipExePath, commandLineArgs, addFileToArchiveCallback, AZ::Uuid::CreateNull(), workingDirectory); - return success; - } - - void ArchiveComponent::AddFilesToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) - { - AZStd::string commandLineArgs = Platform::GetAddFilesToArchiveCommand(archivePath, listFilePath); - if (commandLineArgs.empty()) - { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return; - } - - LaunchZipExe(m_zipExePath, commandLineArgs, respCallback, taskHandle, workingDirectory); - } - - - bool ArchiveComponent::ExtractArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool extractWithRootDirectory) - { - AZStd::string commandLineArgs = Platform::GetExtractArchiveCommand(archivePath, destinationPath, extractWithRootDirectory); - - if (commandLineArgs.empty()) - { - // The platform-specific implementation has already thrown its own error, no need to throw another one - return false; - } - - bool success = false; - auto extractArchiveCallback = [&success](bool result, AZStd::string consoleOutput) { - success = result; - }; - - LaunchZipExe(m_unzipExePath, commandLineArgs, extractArchiveCallback); - return success; - } - - void ArchiveComponent::CancelTasks(AZ::Uuid taskHandle) - { - AZStd::unique_lock lock(m_threadControlMutex); - - auto it = m_threadInfoMap.find(taskHandle); - if (it == m_threadInfoMap.end()) - { - return; - } - - ThreadInfo& info = it->second; - info.shouldStop = true; - m_cv.wait(lock, [&info]() { - return info.threads.size() == 0; - }); - m_threadInfoMap.erase(it); - } - - void ArchiveComponent::LaunchZipExe(const AZStd::string& exePath, const AZStd::string& commandLineArgs, const ArchiveResponseOutputCallback& respCallback, AZ::Uuid taskHandle, const AZStd::string& workingDir, bool captureOutput) - { - auto sevenZJob = [=]() - { - if (!taskHandle.IsNull()) + auto archive = m_archive->OpenArchive(archivePath, {}, AZ::IO::INestedArchive::FLAGS_CREATE_NEW); + if (!archive) { - AZStd::unique_lock lock(m_threadControlMutex); - m_threadInfoMap[taskHandle].threads.insert(AZStd::this_thread::get_id()); - m_cv.notify_all(); + AZ_Error(s_traceName, false, "Failed to create archive file '%s'", archivePath.c_str()); + p.set_value(false); + return; } - AzFramework::ProcessLauncher::ProcessLaunchInfo info; - info.m_commandlineParameters = exePath + " " + commandLineArgs; - - info.m_showWindow = false; - if (!workingDir.empty()) + auto foundFiles = AzFramework::FileFunc::FindFilesInPath(dirToArchive, "*", true); + if (!foundFiles.IsSuccess()) { - info.m_workingDirectory = workingDir; + AZ_Error(s_traceName, false, "Failed to find file listing under directory '%d'", dirToArchive.c_str()); + p.set_value(false); + return; } - AZStd::unique_ptr watcher(AzFramework::ProcessWatcher::LaunchProcess(info, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT)); - AZStd::string consoleOutput; - AZ::u32 exitCode = static_cast(SevenZipExitCode::UserStoppedProcess); - if (watcher) + bool success = true; + AZStd::vector fileBuffer; + const AZ::IO::Path workingPath{ dirToArchive }; + + for (const auto& fileName : foundFiles.GetValue()) { - // callback requires output captured from 7z - if (captureOutput) + bool thisSuccess = false; + + AZ::IO::PathView relativePath = AZ::IO::PathView{ fileName }.LexicallyRelative(workingPath); + + AZ::IO::Path fullPath = (workingPath / relativePath); + if (ArchiveUtils::ReadFile(fullPath, AZ::IO::OpenMode::ModeRead, fileBuffer)) { - AZStd::string consoleBuffer; - while (watcher->IsProcessRunning(&exitCode)) - { - if (!taskHandle.IsNull()) - { - AZStd::unique_lock lock(m_threadControlMutex); - if (m_threadInfoMap[taskHandle].shouldStop) - { - watcher->TerminateProcess(static_cast(SevenZipExitCode::UserStoppedProcess)); - } - } - watcher->WaitForProcessToExit(g_sleepDuration, &exitCode); - AZ::u32 outputSize = watcher->GetCommunicator()->PeekOutput(); - if (outputSize) - { - consoleBuffer.resize(outputSize); - watcher->GetCommunicator()->ReadOutput(consoleBuffer.data(), outputSize); - consoleOutput += consoleBuffer; - } - } + int result = archive->UpdateFile( + relativePath.Native(), fileBuffer.data(), fileBuffer.size(), s_compressionMethod, + s_compressionLevel, s_compressionCodec); + + thisSuccess = (result == AZ::IO::ZipDir::ZD_ERROR_SUCCESS); + AZ_Error( + s_traceName, thisSuccess, "Error %d encountered while adding '%s' to archive '%.*s'", result, fileName.c_str(), + AZ_STRING_ARG(archive->GetFullPath().Native())); } else { - ConsoleEchoCommunicator echoCommunicator(watcher->GetCommunicator()); - while (watcher->IsProcessRunning(&exitCode)) - { - if (!taskHandle.IsNull()) - { - AZStd::unique_lock lock(m_threadControlMutex); - if (m_threadInfoMap[taskHandle].shouldStop) - { - watcher->TerminateProcess(static_cast(SevenZipExitCode::UserStoppedProcess)); - } - } - watcher->WaitForProcessToExit(g_sleepDuration, &exitCode); - echoCommunicator.Pump(); - } + AZ_Error( + s_traceName, false, "Error encountered while reading '%s' to add to archive '%.*s'", fileName.c_str(), + AZ_STRING_ARG(archive->GetFullPath().Native())); } + + success = (success && thisSuccess); } - if (taskHandle.IsNull()) + archive.reset(); + p.set_value(success); + }; + + // Async task... + std::promise p; + std::future f = p.get_future(); + + AZStd::thread_desc threadDesc; + threadDesc.m_name = "Archive Task (Create)"; + m_threads.emplace_back(threadDesc, FnCreateArchive, AZStd::move(p)); + return f; + } + + + std::future ArchiveComponent::ExtractArchive( + const AZStd::string& archivePath, + const AZStd::string& destinationPath) + { + if (!CheckParamsForExtract(archivePath, destinationPath)) + { + std::promise p; + p.set_value(false); + return p.get_future(); + } + + auto FnExtractArchive = [this, archivePath, destinationPath](std::promise&& p) -> void + { + auto archive = m_archive->OpenArchive(archivePath, {}, AZ::IO::INestedArchive::FLAGS_READ_ONLY); + if (!archive) { - respCallback(exitCode == static_cast(SevenZipExitCode::NoError), AZStd::move(consoleOutput)); + AZ_Error(s_traceName, false, "Failed to open archive file '%s'", archivePath.c_str()); + p.set_value(false); + return; + } + + AZStd::vector filesInArchive; + if (int result = archive->ListAllFiles(filesInArchive); result != AZ::IO::ZipDir::ZD_ERROR_SUCCESS) + { + AZ_Error(s_traceName, false, "Failed to get list of files in archive '%s'", archivePath.c_str()); + p.set_value(false); + return; + } + + AZStd::vector fileBuffer; + AZ::IO::Path destination{ destinationPath }; + AZ::u64 fileSize = 0; + AZ::u64 numFilesWritten = 0; + AZ::u64 bytesWritten = 0; + AZ::IO::INestedArchive::Handle srcHandle{}; + AZ::IO::HandleType dstHandle = AZ::IO::InvalidHandle; + constexpr AZ::IO::OpenMode openMode = + (AZ::IO::OpenMode::ModeCreatePath | AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeUpdate); + + for (const auto& filePath : filesInArchive) + { + srcHandle = archive->FindFile(filePath.Native()); + AZ_Assert(srcHandle != nullptr, "File '%s' does not exist inside archive '%s'", filePath.c_str(), archivePath.c_str()); + + fileSize = (srcHandle != nullptr) ? archive->GetFileSize(srcHandle) : 0; + fileBuffer.resize_no_construct(fileSize); + if (auto result = archive->ReadFile(srcHandle, fileBuffer.data()); result != AZ::IO::ZipDir::ZD_ERROR_SUCCESS) + { + AZ_Error( + s_traceName, false, "Failed to read file '%s' in archive '%s' with error %d", filePath.c_str(), archivePath.c_str(), + result); + continue; + } + + AZ::IO::Path destinationFile = destination / filePath; + if (!m_fileIO->Open(destinationFile.c_str(), openMode, dstHandle)) + { + AZ_Error(s_traceName, false, "Failed to open '%s' for writing", destinationFile.c_str()); + continue; + } + + if (!m_fileIO->Write(dstHandle, fileBuffer.data(), fileSize, &bytesWritten)) + { + AZ_Error(s_traceName, false, "Failed to write destination file '%s'", destinationFile.c_str()); + } + else if (bytesWritten == fileSize) + { + ++numFilesWritten; + } + + m_fileIO->Close(dstHandle); + } + + p.set_value(numFilesWritten == filesInArchive.size()); + }; + + // Async task... + std::promise p; + std::future f = p.get_future(); + + AZStd::thread_desc threadDesc; + threadDesc.m_name = "Archive Task (Extract)"; + m_threads.emplace_back(threadDesc, FnExtractArchive, AZStd::move(p)); + return f; + } + + + std::future ArchiveComponent::ExtractFile( + const AZStd::string& archivePath, + const AZStd::string& fileInArchive, + const AZStd::string& destinationPath) + { + if (!CheckParamsForExtract(archivePath, destinationPath)) + { + std::promise p; + p.set_value(false); + return p.get_future(); + } + + auto FnExtractFile = [this, archivePath, fileInArchive, destinationPath](std::promise&& p) -> void + { + auto archive = m_archive->OpenArchive(archivePath, {}, AZ::IO::INestedArchive::FLAGS_READ_ONLY); + if (!archive) + { + AZ_Error(s_traceName, false, "Failed to open archive file '%s'", archivePath.c_str()); + p.set_value(false); + return; + } + + AZ::IO::INestedArchive::Handle fileHandle = archive->FindFile(fileInArchive); + if (!fileHandle) + { + AZ_Error(s_traceName, false, "File '%s' does not exist inside archive '%s'", fileInArchive.c_str(), archivePath.c_str()); + p.set_value(false); + return; + } + + AZ::u64 fileSize = archive->GetFileSize(fileHandle); + AZStd::vector fileBuffer; + fileBuffer.resize_no_construct(fileSize); + + if (auto result = archive->ReadFile(fileHandle, fileBuffer.data()); result != AZ::IO::ZipDir::ZD_ERROR_SUCCESS) + { + AZ_Error( + s_traceName, false, "Failed to read file '%s' in archive '%s' with error %d", fileInArchive.c_str(), + archivePath.c_str(), result); + p.set_value(false); + return; + } + + AZ::IO::HandleType destFileHandle = AZ::IO::InvalidHandle; + AZ::IO::Path destinationFile{ destinationPath }; + destinationFile /= fileInArchive; + AZ::IO::OpenMode openMode = (AZ::IO::OpenMode::ModeCreatePath | AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeUpdate); + if (!m_fileIO->Open(destinationFile.c_str(), openMode, destFileHandle)) + { + AZ_Error(s_traceName, false, "Failed to open destination file '%s' for writing", destinationFile.c_str()); + p.set_value(false); + return; + } + + AZ::u64 bytesWritten = 0; + if (!m_fileIO->Write(destFileHandle, fileBuffer.data(), fileSize, &bytesWritten)) + { + AZ_Error(s_traceName, false, "Failed to write destination file '%s'", destinationFile.c_str()); + } + + m_fileIO->Close(destFileHandle); + p.set_value(bytesWritten == fileSize); + }; + + // Async task... + std::promise p; + std::future f = p.get_future(); + + AZStd::thread_desc threadDesc; + threadDesc.m_name = "Archive Task (Extract Single)"; + m_threads.emplace_back(threadDesc, FnExtractFile, AZStd::move(p)); + return f; + } + + + bool ArchiveComponent::ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector& outFileEntries) + { + if (!m_fileIO || !m_archive) + { + return false; + } + + if (!m_fileIO->Exists(archivePath.c_str())) + { + AZ_Error(s_traceName, false, "Archive '%s' does not exist!", archivePath.c_str()); + return false; + } + + auto archive = m_archive->OpenArchive(archivePath, {}, AZ::IO::INestedArchive::FLAGS_READ_ONLY); + if (!archive) + { + AZ_Error(s_traceName, false, "Failed to open archive file '%s'", archivePath.c_str()); + return false; + } + + AZStd::vector fileEntries; + int result = archive->ListAllFiles(fileEntries); + outFileEntries.clear(); + for (const auto& path : fileEntries) + { + outFileEntries.emplace_back(path.String()); + } + return (result == AZ::IO::ZipDir::ZD_ERROR_SUCCESS); + } + + + std::future ArchiveComponent::AddFileToArchive( + const AZStd::string& archivePath, + const AZStd::string& workingDirectory, + const AZStd::string& fileToAdd) + { + if (!CheckParamsForAdd(workingDirectory, fileToAdd)) + { + std::promise p; + p.set_value(false); + return p.get_future(); + } + + auto FnAddFileToArchive = [this, archivePath, workingDirectory, fileToAdd](std::promise&& p) -> void + { + auto archive = m_archive->OpenArchive(archivePath); + if (!archive) + { + AZ_Error(s_traceName, false, "Failed to open archive file '%s'", archivePath.c_str()); + p.set_value(false); + return; + } + + AZ::IO::Path workingPath{ workingDirectory }; + AZ::IO::Path fullPath = workingPath / fileToAdd; + AZ::IO::PathView relativePath = AZ::IO::PathView{ fullPath }.LexicallyRelative(workingPath); + + AZStd::vector fileBuffer; + bool success = false; + if (ArchiveUtils::ReadFile(fullPath, AZ::IO::OpenMode::ModeRead, fileBuffer)) + { + int result = archive->UpdateFile( + relativePath.Native(), fileBuffer.data(), fileBuffer.size(), s_compressionMethod, + s_compressionLevel, s_compressionCodec); + + success = (result == AZ::IO::ZipDir::ZD_ERROR_SUCCESS); + AZ_Error( + s_traceName, success, "Error %d encountered while adding '%s' to archive '%.*s'", result, fileToAdd.c_str(), + AZ_STRING_ARG(archive->GetFullPath().Native())); } else { - AZ::TickBus::QueueFunction(respCallback, (exitCode == static_cast(SevenZipExitCode::NoError)), AZStd::move(consoleOutput)); + AZ_Error( + s_traceName, false, "Error encountered while reading '%s' to add to archive '%.*s'", fileToAdd.c_str(), + AZ_STRING_ARG(archive->GetFullPath().Native())); } - if (!taskHandle.IsNull()) - { - AZStd::unique_lock lock(m_threadControlMutex); - ThreadInfo& tInfo = m_threadInfoMap[taskHandle]; - tInfo.threads.erase(AZStd::this_thread::get_id()); - m_cv.notify_all(); - } + archive.reset(); + p.set_value(success); }; - if (!taskHandle.IsNull()) - { - AZStd::thread processThread(sevenZJob); - AZStd::unique_lock lock(m_threadControlMutex); - ThreadInfo& info = m_threadInfoMap[taskHandle]; - m_cv.wait(lock, [&info, &processThread]() { - return info.threads.find(processThread.get_id()) != info.threads.end(); - }); - processThread.detach(); - } - else - { - sevenZJob(); - } + + // Async task... + std::promise p; + std::future f = p.get_future(); + + AZStd::thread_desc threadDesc; + threadDesc.m_name = "Archive Task (Add Single)"; + m_threads.emplace_back(threadDesc, FnAddFileToArchive, AZStd::move(p)); + return f; } + + + std::future ArchiveComponent::AddFilesToArchive( + const AZStd::string& archivePath, + const AZStd::string& workingDirectory, + const AZStd::string& listFilePath) + { + if (!CheckParamsForAdd(workingDirectory, listFilePath)) + { + std::promise p; + p.set_value(false); + return p.get_future(); + } + + auto FnAddFilesToArchive = [this, archivePath, workingDirectory, listFilePath](std::promise&& p) -> void + { + auto archive = m_archive->OpenArchive(archivePath); + if (!archive) + { + AZ_Error(s_traceName, false, "Failed to open archive file '%s'", archivePath.c_str()); + p.set_value(false); + return; + } + + bool success = true; // starts true and turns false when any error is encountered. + AZ::IO::Path basePath{ workingDirectory }; + + auto PerLineCallback = [&success, &basePath, &archive](AZStd::string_view filePathLine) -> void + { + AZStd::vector fileBuffer; + AZ::IO::Path fullPath = (basePath / filePathLine); + if (ArchiveUtils::ReadFile(fullPath, AZ::IO::OpenMode::ModeRead, fileBuffer)) + { + int result = archive->UpdateFile( + filePathLine, fileBuffer.data(), fileBuffer.size(), s_compressionMethod, + s_compressionLevel, s_compressionCodec); + + bool thisSuccess = (result == AZ::IO::ZipDir::ZD_ERROR_SUCCESS); + success = (success && thisSuccess); + AZ_Error( + s_traceName, thisSuccess, "Error %d encountered while adding '%.*s' to archive '%.*s'", result, + AZ_STRING_ARG(filePathLine), AZ_STRING_ARG(archive->GetFullPath().Native())); + } + else + { + AZ_Error( + s_traceName, false, "Error encountered while reading '%.*s' to add to archive '%.*s'", AZ_STRING_ARG(filePathLine), + AZ_STRING_ARG(archive->GetFullPath().Native())); + } + }; + + ArchiveUtils::ProcessFileList(listFilePath, PerLineCallback); + + archive.reset(); + p.set_value(success); + }; + + // Async task... + std::promise p; + std::future f = p.get_future(); + + AZStd::thread_desc threadDesc; + threadDesc.m_name = "Archive Task (Add)"; + m_threads.emplace_back(threadDesc, FnAddFilesToArchive, AZStd::move(p)); + return f; + } + + + bool ArchiveComponent::CheckParamsForAdd(const AZStd::string& directory, const AZStd::string& file) + { + if (!m_fileIO || !m_archive) + { + return false; + } + + if (!m_fileIO->IsDirectory(directory.c_str())) + { + AZ_Error( + s_traceName, false, "Working directory '%s' is not a directory or doesn't exist!", directory.c_str()); + return false; + } + + if (!file.empty()) + { + auto filePath = AZ::IO::Path{ directory } / file; + if (!m_fileIO->Exists(filePath.c_str()) || m_fileIO->IsDirectory(filePath.c_str())) + { + AZ_Error(s_traceName, false, "File list '%s' is a directory or doesn't exist!", filePath.c_str()); + return false; + } + } + + return true; + } + + bool ArchiveComponent::CheckParamsForExtract(const AZStd::string& archive, const AZStd::string& directory) + { + if (!m_fileIO || !m_archive) + { + return false; + } + + if (!m_fileIO->Exists(archive.c_str())) + { + AZ_Error(s_traceName, false, "Archive '%s' does not exist!", archive.c_str()); + return false; + } + + if (!m_fileIO->Exists(directory.c_str())) + { + if (!m_fileIO->CreatePath(directory.c_str())) + { + AZ_Error(s_traceName, false, "Failed to create destination directory '%s'", directory.c_str()); + return false; + } + } + + return true; + } + + bool ArchiveComponent::CheckParamsForCreate(const AZStd::string& archive, const AZStd::string& directory) + { + if (!m_fileIO || !m_archive) + { + return false; + } + + if (m_fileIO->Exists(archive.c_str())) + { + AZ_Error(s_traceName, false, "Archive file '%s' already exists, cannot create a new archive there!"); + return false; + } + + if (!m_fileIO->IsDirectory(directory.c_str())) + { + AZ_Error(s_traceName, false, "Directory '%s' is not a directory or doesn't exist!", directory.c_str()); + return false; + } + + return true; + } + } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.h index fc344fc5a6..e2b437bcf2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.h @@ -10,80 +10,76 @@ #include #include +#include #include #include #include #include +#include #include namespace AzToolsFramework { - enum class SevenZipExitCode : AZ::u32 - { - NoError = 0, - Warning = 1, - FatalError = 2, - CommandLineError = 7, - NotEnoughMemory = 8, - UserStoppedProcess = 255 - }; - - // the ArchiveComponent's job is to execute zip commands. - // it parses the status of zip commands and returns results. + // the ArchiveComponent's job is to create and manipulate zip archives. class ArchiveComponent : public AZ::Component - , private ArchiveCommands::Bus::Handler + , private ArchiveCommandsBus::Handler { public: - AZ_COMPONENT(ArchiveComponent, "{A19EEA33-3736-447F-ACF7-DAA4B6A179AA}") + AZ_COMPONENT(ArchiveComponent, "{A19EEA33-3736-447F-ACF7-DAA4B6A179AA}"); ArchiveComponent() = default; ~ArchiveComponent() override = default; + ArchiveComponent(const ArchiveComponent&) = delete; + ArchiveComponent& operator=(const ArchiveComponent&) = delete; + ////////////////////////////////////////////////////////////////////////// // AZ::Component overrides void Activate() override; void Deactivate() override; ////////////////////////////////////////////////////////////////////////// - private: + + protected: static void Reflect(AZ::ReflectContext* context); ////////////////////////////////////////////////////////////////////////// - // ArchiveCommands::Bus::Handler overrides - void CreateArchive(const AZStd::string& archivePath, const AZStd::string& dirToArchive, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - bool CreateArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& dirToArchive) override; - bool ExtractArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool extractWithRootDirectory) override; - void ExtractArchive(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseCallback& respCallback) override; - void ExtractArchiveOutput(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - void ExtractArchiveWithoutRoot(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - void ExtractFile(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - bool ExtractFileBlocking(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite) override; - void ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector& fileEntries, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - bool ListFilesInArchiveBlocking(const AZStd::string& archivePath, AZStd::vector& fileEntries) override; - void AddFileToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& fileToAdd, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - bool AddFileToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& fileToAdd) override; - bool AddFilesToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath) override; - void AddFilesToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - void CancelTasks(AZ::Uuid taskHandle) override; + // ArchiveCommandsBus::Handler overrides + [[nodiscard]] std::future CreateArchive( + const AZStd::string& archivePath, + const AZStd::string& dirToArchive) override; + + [[nodiscard]] std::future ExtractArchive( + const AZStd::string& archivePath, + const AZStd::string& destinationPath) override; + + [[nodiscard]] std::future ExtractFile( + const AZStd::string& archivePath, + const AZStd::string& fileInArchive, + const AZStd::string& destinationPath) override; + + bool ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector& outFileEntries) override; + + [[nodiscard]] std::future AddFileToArchive( + const AZStd::string& archivePath, + const AZStd::string& workingDirectory, + const AZStd::string& fileToAdd) override; + + [[nodiscard]] std::future AddFilesToArchive( + const AZStd::string& archivePath, + const AZStd::string& workingDirectory, + const AZStd::string& listFilePath) override; ////////////////////////////////////////////////////////////////////////// - - // Launches the input zip exe as a background child process in a detached background thread, if the task handle is not null - // otherwise launches input zip exe in the calling thread. - void LaunchZipExe(const AZStd::string& exePath, const AZStd::string& commandLineArgs, const ArchiveResponseOutputCallback& respCallback, AZ::Uuid taskHandle = AZ::Uuid::CreateNull(), const AZStd::string& workingDir = "", bool captureOutput = false); - AZStd::string m_zipExePath; - AZStd::string m_unzipExePath; + private: + AZ::IO::FileIOBase* m_fileIO = nullptr; + AZ::IO::IArchive* m_archive = nullptr; + AZStd::vector m_threads; - // Struct for tracking background threads/tasks - struct ThreadInfo - { - bool shouldStop = false; - AZStd::set threads; - }; - - AZStd::mutex m_threadControlMutex; // Guards m_threadInfoMap - AZStd::condition_variable m_cv; - AZStd::unordered_map m_threadInfoMap; + bool CheckParamsForAdd(const AZStd::string& directory, const AZStd::string& file); + bool CheckParamsForExtract(const AZStd::string& archive, const AZStd::string& directory); + bool CheckParamsForCreate(const AZStd::string& archive, const AZStd::string& directory); }; + } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/NullArchiveComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/NullArchiveComponent.cpp index f82724a721..972e9d588f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/NullArchiveComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/NullArchiveComponent.cpp @@ -16,91 +16,62 @@ namespace AzToolsFramework void NullArchiveComponent::Activate() { - ArchiveCommands::Bus::Handler::BusConnect(); + ArchiveCommandsBus::Handler::BusConnect(); } void NullArchiveComponent::Deactivate() { - ArchiveCommands::Bus::Handler::BusDisconnect(); + ArchiveCommandsBus::Handler::BusDisconnect(); } - bool NullArchiveComponent::ExtractArchiveBlocking(const AZStd::string& /*archivePath*/, const AZStd::string& /*destinationPath*/, bool /*extractWithRootDirectory*/) + std::future DefaultFuture() + { + std::promise p; + p.set_value(false); + return p.get_future(); + } + + std::future NullArchiveComponent::CreateArchive( + const AZStd::string& /*archivePath*/, + const AZStd::string& /*dirToArchive*/) + { + return DefaultFuture(); + } + + std::future NullArchiveComponent::ExtractArchive( + const AZStd::string& /*archivePath*/, + const AZStd::string& /*destinationPath*/) + { + return DefaultFuture(); + } + + std::future NullArchiveComponent::ExtractFile( + const AZStd::string& /*archivePath*/, + const AZStd::string& /*fileInArchive*/, + const AZStd::string& /*destinationPath*/) + { + return DefaultFuture(); + } + + bool NullArchiveComponent::ListFilesInArchive(const AZStd::string& /*archivePath*/, AZStd::vector& /*outFileEntries*/) { return false; } - void NullArchiveComponent::ExtractArchive(const AZStd::string& /*archivePath*/, const AZStd::string& /*destinationPath*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseCallback& respCallback) + std::future NullArchiveComponent::AddFileToArchive( + const AZStd::string& /*archivePath*/, + const AZStd::string& /*fileToAdd*/, + const AZStd::string& /*pathInArchive*/) { - AZ::TickBus::QueueFunction(respCallback, false); + return DefaultFuture(); } - void NullArchiveComponent::ExtractArchiveOutput(const AZStd::string& /*archivePath*/, const AZStd::string& /*destinationPath*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback) - { - AZ::TickBus::QueueFunction(respCallback, false, AZStd::string()); - } - - void NullArchiveComponent::ExtractArchiveWithoutRoot(const AZStd::string& /*archivePath*/, const AZStd::string& /*destinationPath*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback) - { - AZ::TickBus::QueueFunction(respCallback, false, AZStd::string()); - } - - void NullArchiveComponent::ExtractFile(const AZStd::string& /*archivePath*/, const AZStd::string& /*fileInArchive*/, const AZStd::string& /*destinationPath*/, bool /*overWrite*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback) - { - // Always report we failed to extract - AZ::TickBus::QueueFunction(respCallback, false, AZStd::string()); - } - - bool NullArchiveComponent::ExtractFileBlocking(const AZStd::string& /*archivePath*/, const AZStd::string& /*fileInArchive*/, const AZStd::string& /*destinationPath*/, bool /*overWrite*/) - { - return false; - } - - void NullArchiveComponent::ListFilesInArchive(const AZStd::string& /*archivePath*/, AZStd::vector& /*consoleOutput*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback) - { - // Always report we failed to extract - AZ::TickBus::QueueFunction(respCallback, false, AZStd::string()); - } - - bool NullArchiveComponent::ListFilesInArchiveBlocking(const AZStd::string& /*archivePath*/, AZStd::vector& /*consoleOutput*/) - { - return false; - } - - void NullArchiveComponent::AddFileToArchive(const AZStd::string& /*archivePath*/, const AZStd::string& /*fileToAdd*/, const AZStd::string& /*pathInArchive*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback) - { - // Always report we failed to extract - AZ::TickBus::QueueFunction(respCallback, false, AZStd::string()); - } - - bool NullArchiveComponent::AddFileToArchiveBlocking(const AZStd::string& /*archivePath*/, const AZStd::string& /*fileToAdd*/, const AZStd::string& /*pathInArchive*/) - { - return false; - } - - bool NullArchiveComponent::AddFilesToArchiveBlocking(const AZStd::string& /*archivePath*/, const AZStd::string& /*workingDirectory*/, const AZStd::string& /*listFilePath*/) - { - return false; - } - - void NullArchiveComponent::AddFilesToArchive(const AZStd::string& /*archivePath*/, const AZStd::string& /*workingDirectory*/, const AZStd::string& /*listFilePath*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback) - { - // Always report we failed to extract - AZ::TickBus::QueueFunction(respCallback, false, AZStd::string()); - } - - void NullArchiveComponent::CreateArchive(const AZStd::string& /*archivePath*/, const AZStd::string& /*dirToArchive*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback) - { - // Always report we failed to extract - AZ::TickBus::QueueFunction(respCallback, false, AZStd::string()); - } - - bool NullArchiveComponent::CreateArchiveBlocking(const AZStd::string& /*archivePath*/, const AZStd::string& /*dirToArchive*/) - { - return false; - } - - void NullArchiveComponent::CancelTasks(AZ::Uuid /*taskHandle*/) + std::future NullArchiveComponent::AddFilesToArchive( + const AZStd::string& /*archivePath*/, + const AZStd::string& /*workingDirectory*/, + const AZStd::string& /*listFilePath*/) { + return DefaultFuture(); } void NullArchiveComponent::Reflect(AZ::ReflectContext* context) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/NullArchiveComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/NullArchiveComponent.h index 2023490351..9ce33d0c85 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/NullArchiveComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/NullArchiveComponent.h @@ -15,7 +15,7 @@ namespace AzToolsFramework { class NullArchiveComponent : public AZ::Component - , private ArchiveCommands::Bus::Handler + , private ArchiveCommandsBus::Handler { public: AZ_COMPONENT(NullArchiveComponent, "{D665B6B1-5FF4-4203-B19F-BBDB82587129}") @@ -32,23 +32,31 @@ namespace AzToolsFramework static void Reflect(AZ::ReflectContext* context); ////////////////////////////////////////////////////////////////////////// - // ArchiveCommands::Bus::Handler overrides - // ArchiveCommands::Bus::Handler overrides - void CreateArchive(const AZStd::string& archivePath, const AZStd::string& dirToArchive, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - bool CreateArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& dirToArchive) override; - bool ExtractArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool extractWithRootDirectory) override; - void ExtractArchive(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseCallback& respCallback) override; - void ExtractArchiveOutput(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - void ExtractArchiveWithoutRoot(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - void ExtractFile(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - bool ExtractFileBlocking(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite) override; - void ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector& consoleOutput, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - bool ListFilesInArchiveBlocking(const AZStd::string& archivePath, AZStd::vector& consoleOutput) override; - void AddFileToArchive(const AZStd::string& archivePath, const AZStd::string& fileToAdd, const AZStd::string& pathInArchive, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - bool AddFileToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& fileToAdd, const AZStd::string& pathInArchive) override; - bool AddFilesToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath) override; - void AddFilesToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override; - void CancelTasks(AZ::Uuid taskHandle) override; + // ArchiveCommandsBus::Handler overrides + [[nodiscard]] std::future CreateArchive( + const AZStd::string& archivePath, + const AZStd::string& dirToArchive) override; + + [[nodiscard]] std::future ExtractArchive( + const AZStd::string& archivePath, + const AZStd::string& destinationPath) override; + + [[nodiscard]] std::future ExtractFile( + const AZStd::string& archivePath, + const AZStd::string& fileInArchive, + const AZStd::string& destinationPath) override; + + bool ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector& outFileEntries) override; + + [[nodiscard]] std::future AddFileToArchive( + const AZStd::string& archivePath, + const AZStd::string& workingDirectory, + const AZStd::string& fileToAdd) override; + + [[nodiscard]] std::future AddFilesToArchive( + const AZStd::string& archivePath, + const AZStd::string& workingDirectory, + const AZStd::string& listFilePath) override; ////////////////////////////////////////////////////////////////////////// }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.cpp index 7083737cf7..8924907e81 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.cpp @@ -32,12 +32,10 @@ namespace AzToolsFramework const int NumOfBytesInMB = 1024 * 1024; const int ManifestFileSizeBufferInBytes = 10 * 1024; // 10 KB const float AssetCatalogFileSizeBufferPercentage = 1.0f; - using ArchiveCommandsBus = AzToolsFramework::ArchiveCommands::Bus; using AssetCatalogRequestBus = AZ::Data::AssetCatalogRequestBus; const char AssetBundleComponent::DeltaCatalogName[] = "DeltaCatalog.xml"; - constexpr int SleepTimeMS = 250; constexpr int InjectFileRetryCount = 4; @@ -136,7 +134,7 @@ namespace AzToolsFramework AZ_TracePrintf(logWindowName, "Gathering file entries in source pak file \"%s\".\n", sourcePak.c_str()); bool result = false; AZStd::vector fileEntries; - ArchiveCommandsBus::BroadcastResult(result, &AzToolsFramework::ArchiveCommands::ListFilesInArchiveBlocking, normalizedSourcePakPath, fileEntries); + ArchiveCommandsBus::BroadcastResult(result, &AzToolsFramework::ArchiveCommandsBus::Events::ListFilesInArchive, normalizedSourcePakPath, fileEntries); // This ebus currently always returns false as the result, as it is believed that the 7z process is // being terminated by the user instead of ending gracefully. Check against an empty fileList instead // as a result. @@ -606,15 +604,17 @@ namespace AzToolsFramework { AZ_TracePrintf(logWindowName, "Injecting file (%s) into bundle (%s).\n", filePath.c_str(), archiveFilePath.c_str()); bool fileAddedToArchive = false; + std::future fileAdded; int retryCount = InjectFileRetryCount; + while (!fileAddedToArchive && retryCount) { - ArchiveCommandsBus::BroadcastResult(fileAddedToArchive, &AzToolsFramework::ArchiveCommands::AddFileToArchiveBlocking, archiveFilePath, workingDirectory, filePath); + ArchiveCommandsBus::BroadcastResult(fileAdded, &AzToolsFramework::ArchiveCommandsBus::Events::AddFileToArchive, archiveFilePath, workingDirectory, filePath); --retryCount; + fileAddedToArchive = fileAdded.get(); if (!fileAddedToArchive && retryCount) { AZ_Error(logWindowName, false, "Failed to insert file (%s) into bundle (%s). Retrying.", filePath.c_str(), archiveFilePath.c_str()); - AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(SleepTimeMS)); } } @@ -627,7 +627,11 @@ namespace AzToolsFramework bool AssetBundleComponent::InjectFile(const AZStd::string& filePath, const AZStd::string& sourcePak) { - return InjectFile(filePath, sourcePak, ""); + // When no working directory is specified, assume that the file being injected goes into the root of the archive. + // The filePath should be an absolute path, making the workingDirectory be the path leading up to the file. + AZ::IO::PathView fullFilePath{ filePath, AZ::IO::PosixPathSeparator }; + AZ::IO::Path workingDir{ fullFilePath.ParentPath() }; + return InjectFile(filePath, sourcePak, workingDir.c_str()); } bool AssetBundleComponent::InjectFiles(const AZStd::vector& fileEntries, const AZStd::string& sourcePak, const char* workingDirectory) @@ -668,8 +672,9 @@ namespace AzToolsFramework } } - bool filesAddedToArchive = false; - AzToolsFramework::ArchiveCommandsBus::BroadcastResult(filesAddedToArchive, &AzToolsFramework::ArchiveCommands::AddFilesToArchiveBlocking, sourcePak, workingDirectory, listFilePath); + std::future filesAdded; + AzToolsFramework::ArchiveCommandsBus::BroadcastResult(filesAdded, &AzToolsFramework::ArchiveCommands::AddFilesToArchive, sourcePak, workingDirectory, listFilePath); + bool filesAddedToArchive = filesAdded.get(); if (!filesAddedToArchive) { AZ_Error(logWindowName, false, "Failed to insert files into bundle (%s).\n", sourcePak.c_str()); @@ -688,7 +693,6 @@ namespace AzToolsFramework { // open the manifest and deserialize it bool manifestExtracted = false; - const bool overwriteExisting = true; TemporaryDir tempDir(sourcePak); if (!tempDir.m_result) @@ -698,7 +702,10 @@ namespace AzToolsFramework AZStd::string manifestFilePath; AzFramework::StringFunc::Path::ConstructFull(tempDir.m_tempFolderPath.c_str(), AzFramework::AssetBundleManifest::s_manifestFileName, manifestFilePath, true); - ArchiveCommandsBus::BroadcastResult(manifestExtracted, &ArchiveCommandsBus::Events::ExtractFileBlocking, sourcePak, AzFramework::AssetBundleManifest::s_manifestFileName, tempDir.m_tempFolderPath, overwriteExisting); + + std::future extractResult; + ArchiveCommandsBus::BroadcastResult(extractResult, &ArchiveCommandsBus::Events::ExtractFile, sourcePak, AzFramework::AssetBundleManifest::s_manifestFileName, tempDir.m_tempFolderPath); + manifestExtracted = extractResult.get(); if (!manifestExtracted) { AZ_Error(logWindowName, false, "Failed to extract existing manifest from archive \"%s\".", sourcePak.c_str()); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.h index 307777cc1b..17a9dd40f5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBundle/AssetBundleComponent.h @@ -57,7 +57,7 @@ namespace AzToolsFramework //! Returns true if the file at filePath was successfully injected into the bundle at sourcePak static bool InjectFile(const AZStd::string& filePath, const AZStd::string& sourcePak, const char* workingDirectory); - //! Inject the files with relative filePaths which espect to the working directory into the bundle at sourcePak + //! Inject the files with relative filePaths with respect to the working directory into the bundle at sourcePak //! Returns true if the file at filePath was successfully injected into the bundle at sourcePak static bool InjectFiles(const AZStd::vector& fileEntries, const AZStd::string& sourcePak, const char* workingDirectory); diff --git a/Code/Framework/AzToolsFramework/Platform/Linux/AzToolsFramework/Archive/ArchiveComponent_Linux.cpp b/Code/Framework/AzToolsFramework/Platform/Linux/AzToolsFramework/Archive/ArchiveComponent_Linux.cpp deleted file mode 100644 index cc8b9492e8..0000000000 --- a/Code/Framework/AzToolsFramework/Platform/Linux/AzToolsFramework/Archive/ArchiveComponent_Linux.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/* - * 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 -#include -#include -#include - -namespace AzToolsFramework -{ - namespace Platform - { - [[maybe_unused]] static const char ErrorChannel[] = "ArchiveComponent_Linux"; - - static const char ZipExePath[] = R"(/usr/bin/zip)"; - static const char UnzipExePath[] = R"(/usr/bin/unzip)"; - - static const char CreateArchiveCmd[] = "-r \"%s\" . -i *"; - - static const char ExtractArchiveCmd[] = R"(-o "%s" -d "%s")"; - - static const char AddFileCmd[] = R"("%s" "%s")"; - - static const char ExtractFileCmd[] = R"(%s "%s" %s)"; - static const char ExtractFileDestination[] = R"(%s "%s" "%s" -d "%s")"; - static const char ExtractOverwrite[] = "-o"; - static const char ExtractSkipExisting[] = "-n"; - static const char ListFilesInArchiveCmd[] = "-l %s"; - - AZStd::string GetZipExePath() - { - return ZipExePath; - } - - AZStd::string GetUnzipExePath() - { - return UnzipExePath; - } - - AZ::Outcome MakePath(const AZStd::string& path) - { - // Create the folder if it does not already exist - if (!AZ::IO::FileIOBase::GetInstance()->Exists(path.c_str())) - { - auto result = AZ::IO::FileIOBase::GetInstance()->CreatePath(path.c_str()); - if (!result) - { - return AZ::Failure(AZStd::string::format("Path creation failed. Input path: %s \n", path.c_str())); - } - } - - return AZ::Success(path); - } - - AZ::Outcome MakeCreateArchivePath(const AZStd::string& archivePath) - { - // Remove the file name from the input path - // /some/folder/path/archive.zip -> /some/folder/path/ - AZStd::string strippedArchivePath = archivePath; - AzFramework::StringFunc::Path::StripFullName(strippedArchivePath); - - if (strippedArchivePath.empty()) - { - return AZ::Failure(AZStd::string::format("Stripped path name is empty. Cancelling path creation. Input path: %s\n", archivePath.c_str())); - } - - return MakePath(strippedArchivePath); - } - - AZ::Outcome MakeExtractArchivePath(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool includeRoot) - { - if(!includeRoot) - { - // Create the folder for the input destination path with no modifications - // /path/to/destination/ - return MakePath(destinationPath); - } - - // Get the name of the input archive. This will be the name of the root folder for the archive extraction - // /some/folder/path/archive.zip -> archive - AZStd::string zipFileName; - bool result = AzFramework::StringFunc::Path::GetFileName(archivePath.c_str(), zipFileName); - if(!result) - { - return AZ::Failure(AZStd::string::format("Failed to get name of zip file from the archive path. Cancelling path creation. \n Input Archive Path: %s \n", archivePath.c_str())); - } - - // Append the root folder name to the end of the destination path - // /path/to/destination/ + archive -> /path/to/destination/archive - AZStd::string destinationPathWithRoot; - result = AzFramework::StringFunc::Path::Join(destinationPath.c_str(), zipFileName.c_str(), destinationPathWithRoot); - if(!result) - { - return AZ::Failure(AZStd::string::format("Failed to append zip file name to the destination path. Cancelling path creation. \n Destination Path: %s \n Zip file name: %s \n", destinationPath.c_str(), zipFileName.c_str())); - } - - // Append a separator so that it is formatted like a folder - // /path/to/destination/archive -> /path/to/destination/archive/ - AzFramework::StringFunc::Path::AppendSeparator(destinationPathWithRoot); - return MakePath(destinationPathWithRoot); - } - - AZStd::string GetCreateArchiveCommand(const AZStd::string& archivePath, const AZStd::string& dirToArchive) - { - auto pathCreationResult = MakeCreateArchivePath(archivePath); - if (!pathCreationResult) - { - AZ_Error(ErrorChannel, false, "%s", pathCreationResult.GetError().c_str()); - return ""; - } - AZ_UNUSED(dirToArchive); - return AZStd::string::format(CreateArchiveCmd, archivePath.c_str()); - } - - AZStd::string GetExtractArchiveCommand(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool includeRoot) - { - auto pathCreationResult = MakeExtractArchivePath(archivePath, destinationPath, includeRoot); - if (!pathCreationResult) - { - AZ_Error(ErrorChannel, false, "%s", pathCreationResult.GetError().c_str()); - return ""; - } - - return AZStd::string::format(ExtractArchiveCmd, archivePath.c_str(), pathCreationResult.GetValue().c_str()); - } - - AZStd::string GetAddFilesToArchiveCommand(const AZStd::string& /*archivePath*/, const AZStd::string& /*listFilePath*/) - { - // Adding files into a archive using a list file is not currently supported - return {}; - } - - bool IsAddFilesToArchiveCommandSupported() - { - // Adding files into a archive using a list file is not currently supported - return false; - } - - AZStd::string GetAddFileToArchiveCommand(const AZStd::string& archivePath, const AZStd::string& file) - { - if (!MakeCreateArchivePath(archivePath).IsSuccess()) - { - AZ_Error(ErrorChannel, false, "Unable to make path for ( %s ).\n", archivePath.c_str()); - return {}; - } - return AZStd::string::format(AddFileCmd, archivePath.c_str(), file.c_str()); - } - - AZStd::string GetExtractFileCommand(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite) - { - AZStd::string commandLineArgs; - if (destinationPath.empty()) - { - // Extract file in archive from archive path to the current directory, overwriting a file of the same name that exists there. - commandLineArgs = AZStd::string::format(ExtractFileCmd, overWrite ? ExtractOverwrite : ExtractSkipExisting, archivePath.c_str(), fileInArchive.c_str()); - } - else - { - if (!MakePath(destinationPath).IsSuccess()) - { - AZ_Error(ErrorChannel, false, "Unable to make path ( %s ).\n", destinationPath.c_str()); - return {}; - } - // Extract file in archive from archive path to destinationPath, overwriting a file of the same name that exists there. - commandLineArgs = AZStd::string::format(ExtractFileDestination, overWrite ? ExtractOverwrite : ExtractSkipExisting, archivePath.c_str(), fileInArchive.c_str(), destinationPath.c_str()); - } - - return commandLineArgs; - } - - AZStd::string GetListFilesInArchiveCommand(const AZStd::string& archivePath) - { - AZStd::string commandLineArgs = AZStd::string::format(ListFilesInArchiveCmd, archivePath.c_str()); - return commandLineArgs; - } - - /* - Sample Console Output of the unzip list command - - Archive: /var/folders/1q/12nyzqc913qgm532y2c98mnm6w4_qv/T/ArchiveTests-ra8oMy/TestArchive.pak - Length Date Time Name - --------- ---------- ----- ---- - 0 10-14-2019 15:22 testfolder/ - 1 10-14-2019 15:22 testfolder/folderfile.txt - 1 10-14-2019 15:22 basicfile.txt - 1 10-14-2019 15:22 basicfile2.txt - 0 10-14-2019 15:22 testfolder2/ - 1 10-14-2019 15:22 testfolder2/sharedfolderfile2.txt - 1 10-14-2019 15:22 testfolder2/sharedfolderfile.txt - 0 10-14-2019 15:22 testfolder3/ - 0 10-14-2019 15:22 testfolder3/testfolder4/ - 1 10-14-2019 15:22 testfolder3/testfolder4/depthfile.bat - --------- ------- - 6 10 files - */ - - void ParseConsoleOutputFromListFilesInArchive(const AZStd::string& consoleOutput, AZStd::vector& fileEntries) - { - AZStd::vector fileEntryData; - AzFramework::StringFunc::Tokenize(consoleOutput.c_str(), fileEntryData, "\n"); - int startingLineIdx = 3; // first line that might contain the file name - for (size_t lineIdx = startingLineIdx; lineIdx < fileEntryData.size(); ++lineIdx) - { - AZStd::string& line = fileEntryData[lineIdx]; - AZStd::vector lineEntryData; - AzFramework::StringFunc::Tokenize(line.c_str(), lineEntryData, " "); - AZStd::string& fileName = lineEntryData.back(); - - if(fileName.back() == AZ_CORRECT_FILESYSTEM_SEPARATOR) - { - // if the filename ends with a separator - // than it indicates that this is a directory - continue; - } - - if(fileName.compare("-------") == 0) - { - return; - } - - fileEntries.emplace_back(fileName); - } - } - } // namespace Platform -} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/Platform/Linux/platform_linux_files.cmake b/Code/Framework/AzToolsFramework/Platform/Linux/platform_linux_files.cmake index 84d1cf808f..c2c5a11c4c 100644 --- a/Code/Framework/AzToolsFramework/Platform/Linux/platform_linux_files.cmake +++ b/Code/Framework/AzToolsFramework/Platform/Linux/platform_linux_files.cmake @@ -7,5 +7,4 @@ # set(FILES - AzToolsFramework/Archive/ArchiveComponent_Linux.cpp ) diff --git a/Code/Framework/AzToolsFramework/Platform/Mac/AzToolsFramework/Archive/ArchiveComponent_Mac.cpp b/Code/Framework/AzToolsFramework/Platform/Mac/AzToolsFramework/Archive/ArchiveComponent_Mac.cpp deleted file mode 100644 index 67b7b9cf66..0000000000 --- a/Code/Framework/AzToolsFramework/Platform/Mac/AzToolsFramework/Archive/ArchiveComponent_Mac.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* - * 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 -#include -#include -#include - -namespace AzToolsFramework -{ - namespace Platform - { - const char ErrorChannel[] = "ArchiveComponent_OSX"; - - const char ZipExePath[] = R"(/usr/bin/zip)"; - const char UnzipExePath[] = R"(/usr/bin/unzip)"; - - // v Requires investigation, the correct cmd should be R"(-r "%s" "%s/")" but tests fail - const char CreateArchiveCmd[] = R"(-r "%s" .)"; - - const char ExtractArchiveCmd[] = R"(-o "%s" -d "%s")"; - - const char AddFileCmd[] = R"("%s" "%s" -X)"; - const char AddFilesCmd[] = R"("%s" -X %s)"; - - const char ExtractFileCmd[] = R"(%s "%s" %s)"; - const char ExtractFileDestination[] = R"(%s "%s" "%s" -d "%s")"; - const char ExtractOverwrite[] = "-o"; - const char ExtractSkipExisting[] = "-n"; - const char ListFilesInArchiveCmd[] = "-l %s"; - - AZStd::string GetZipExePath() - { - return ZipExePath; - } - - AZStd::string GetUnzipExePath() - { - return UnzipExePath; - } - - AZ::Outcome MakePath(const AZStd::string& path) - { - // Create the folder if it does not already exist - if (!AZ::IO::FileIOBase::GetInstance()->Exists(path.c_str())) - { - auto result = AZ::IO::FileIOBase::GetInstance()->CreatePath(path.c_str()); - if (!result) - { - return AZ::Failure(AZStd::string::format("Path creation failed. Input path: %s \n", path.c_str())); - } - } - - return AZ::Success(path); - } - - AZ::Outcome MakeCreateArchivePath(const AZStd::string& archivePath) - { - // Remove the file name from the input path - // /some/folder/path/archive.zip -> /some/folder/path/ - AZStd::string strippedArchivePath = archivePath; - AzFramework::StringFunc::Path::StripFullName(strippedArchivePath); - - if (strippedArchivePath.empty()) - { - return AZ::Failure(AZStd::string::format("Stripped path name is empty. Cancelling path creation. Input path: %s\n", archivePath.c_str())); - } - - return MakePath(strippedArchivePath); - } - - AZ::Outcome MakeExtractArchivePath(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool includeRoot) - { - if(!includeRoot) - { - // Create the folder for the input destination path with no modifications - // /path/to/destination/ - return MakePath(destinationPath); - } - - // Get the name of the input archive. This will be the name of the root folder for the archive extraction - // /some/folder/path/archive.zip -> archive - AZStd::string zipFileName; - bool result = AzFramework::StringFunc::Path::GetFileName(archivePath.c_str(), zipFileName); - if(!result) - { - return AZ::Failure(AZStd::string::format("Failed to get name of zip file from the archive path. Cancelling path creation. \n Input Archive Path: %s \n", archivePath.c_str())); - } - - // Append the root folder name to the end of the destination path - // /path/to/destination/ + archive -> /path/to/destination/archive - AZStd::string destinationPathWithRoot; - result = AzFramework::StringFunc::Path::Join(destinationPath.c_str(), zipFileName.c_str(), destinationPathWithRoot); - if(!result) - { - return AZ::Failure(AZStd::string::format("Failed to append zip file name to the destination path. Cancelling path creation. \n Destination Path: %s \n Zip file name: %s \n", destinationPath.c_str(), zipFileName.c_str())); - } - - // Append a separator so that it is formatted like a folder - // /path/to/destination/archive -> /path/to/destination/archive/ - AzFramework::StringFunc::Path::AppendSeparator(destinationPathWithRoot); - return MakePath(destinationPathWithRoot); - } - - AZStd::string GetCreateArchiveCommand(const AZStd::string& archivePath, const AZStd::string& dirToArchive) - { - auto pathCreationResult = MakeCreateArchivePath(archivePath); - if (!pathCreationResult.IsSuccess()) - { - AZ_Error(ErrorChannel, false, pathCreationResult.GetError().c_str()); - return ""; - } - - // LY-116692. Requires proper investigation, the correct format should be: - // AZStd::string::format(CreateArchiveCmd, archivePath.c_str(), dirToArchive.c_str()); - // but unit test ArchiveTest.ListFilesInArchiveBlocking_FilesAtThreeDepths_FilesFound fails - AZ_UNUSED(dirToArchive); - return AZStd::string::format(CreateArchiveCmd, archivePath.c_str()); - } - - AZStd::string GetExtractArchiveCommand(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool includeRoot) - { - auto pathCreationResult = MakeExtractArchivePath(archivePath, destinationPath, includeRoot); - if (!pathCreationResult) - { - AZ_Error(ErrorChannel, false, pathCreationResult.GetError().c_str()); - return ""; - } - - return AZStd::string::format(ExtractArchiveCmd, archivePath.c_str(), pathCreationResult.GetValue().c_str()); - } - - AZStd::string GetAddFilesToArchiveCommand(const AZStd::string& archivePath, const AZStd::string& listFilePath) - { - auto pathCreationResult = MakeCreateArchivePath(archivePath); - if (!pathCreationResult) - { - AZ_Error(ErrorChannel, false, pathCreationResult.GetError().c_str()); - return ""; - } - AZStd::string fileListStr; - - { - AZ::IO::FileIOStream fileStream(listFilePath.c_str(), AZ::IO::OpenMode::ModeRead | AZ::IO::OpenMode::ModeText); - if (fileStream.IsOpen()) - { - AZ::IO::SizeType length = fileStream.GetLength(); - AZStd::vector charBuffer; - charBuffer.resize_no_construct(length + 1); - - fileStream.Read(length, charBuffer.data()); - charBuffer.back() = 0; - - fileListStr.append("\""); - fileListStr.insert(1, charBuffer.data()); - AzFramework::StringFunc::Replace(fileListStr, "\n", "\" \""); - fileListStr.append("\""); - } - else - { - AZ_Error(ErrorChannel, false, "Unable to read list file ( %s ) \n", listFilePath.c_str()); - return ""; - } - } - - return AZStd::string::format(AddFilesCmd, archivePath.c_str(), fileListStr.c_str()); - } - - AZStd::string GetAddFileToArchiveCommand(const AZStd::string& archivePath, const AZStd::string& file) - { - auto pathCreationResult = MakeCreateArchivePath(archivePath); - if (!pathCreationResult) - { - AZ_Error(ErrorChannel, false, pathCreationResult.GetError().c_str()); - return ""; - } - - return AZStd::string::format(AddFileCmd, archivePath.c_str(), file.c_str()); - } - - AZStd::string GetExtractFileCommand(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite) - { - AZStd::string commandLineArgs; - if (destinationPath.empty()) - { - // Extract file in archive from archive path to the current directory, overwriting a file of the same name that exists there. - commandLineArgs = AZStd::string::format(ExtractFileCmd, overWrite ? ExtractOverwrite : ExtractSkipExisting, archivePath.c_str(), fileInArchive.c_str()); - } - else - { - if (!MakePath(destinationPath).IsSuccess()) - { - AZ_Error(ErrorChannel, false, "Unable to make path ( %s ).\n", destinationPath.c_str()); - return ""; - } - // Extract file in archive from archive path to destinationPath, overwriting a file of the same name that exists there. - commandLineArgs = AZStd::string::format(ExtractFileDestination, overWrite ? ExtractOverwrite : ExtractSkipExisting, archivePath.c_str(), fileInArchive.c_str(), destinationPath.c_str()); - } - - return commandLineArgs; - } - - AZStd::string GetListFilesInArchiveCommand(const AZStd::string& archivePath) - { - AZStd::string commandLineArgs = AZStd::string::format(ListFilesInArchiveCmd, archivePath.c_str()); - return commandLineArgs; - } - - /* - Sample Console Output of the unzip list command - - Archive: /var/folders/1q/12nyzqc913qgm532y2c98mnm6w4_qv/T/ArchiveTests-ra8oMy/TestArchive.pak - Length Date Time Name - --------- ---------- ----- ---- - 0 10-14-2019 15:22 testfolder/ - 1 10-14-2019 15:22 testfolder/folderfile.txt - 1 10-14-2019 15:22 basicfile.txt - 1 10-14-2019 15:22 basicfile2.txt - 0 10-14-2019 15:22 testfolder2/ - 1 10-14-2019 15:22 testfolder2/sharedfolderfile2.txt - 1 10-14-2019 15:22 testfolder2/sharedfolderfile.txt - 0 10-14-2019 15:22 testfolder3/ - 0 10-14-2019 15:22 testfolder3/testfolder4/ - 1 10-14-2019 15:22 testfolder3/testfolder4/depthfile.bat - --------- ------- - 6 10 files - */ - - void ParseConsoleOutputFromListFilesInArchive(const AZStd::string& consoleOutput, AZStd::vector& fileEntries) - { - AZStd::vector fileEntryData; - AzFramework::StringFunc::Tokenize(consoleOutput.c_str(), fileEntryData, "\n"); - int startingLineIdx = 3; // first line that might contain the file name - for (size_t lineIdx = startingLineIdx; lineIdx < fileEntryData.size(); ++lineIdx) - { - AZStd::string& line = fileEntryData[lineIdx]; - AZStd::vector lineEntryData; - AzFramework::StringFunc::Tokenize(line.c_str(), lineEntryData, " "); - AZStd::string& fileName = lineEntryData.back(); - - if(fileName.back() == AZ_CORRECT_FILESYSTEM_SEPARATOR) - { - // if the filename ends with a separator - // than it indicates that this is a directory - continue; - } - - if(fileName.compare("-------") == 0) - { - return; - } - - fileEntries.emplace_back(fileName); - } - } - - } // namespace Platform -} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/Platform/Mac/platform_mac_files.cmake b/Code/Framework/AzToolsFramework/Platform/Mac/platform_mac_files.cmake index 9928584f86..c2c5a11c4c 100644 --- a/Code/Framework/AzToolsFramework/Platform/Mac/platform_mac_files.cmake +++ b/Code/Framework/AzToolsFramework/Platform/Mac/platform_mac_files.cmake @@ -7,5 +7,4 @@ # set(FILES - AzToolsFramework/Archive/ArchiveComponent_Mac.cpp ) diff --git a/Code/Framework/AzToolsFramework/Platform/Windows/AzToolsFramework/Archive/ArchiveComponent_Windows.cpp b/Code/Framework/AzToolsFramework/Platform/Windows/AzToolsFramework/Archive/ArchiveComponent_Windows.cpp deleted file mode 100644 index 20f53af18b..0000000000 --- a/Code/Framework/AzToolsFramework/Platform/Windows/AzToolsFramework/Archive/ArchiveComponent_Windows.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* - * 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 -#include -#include -#include - -namespace AzToolsFramework -{ - namespace Platform - { - const char CreateArchiveCmd[] = R"(a -tzip -mx=1 "%s" -r "%s\*")"; - - // -aos is for skipping extract on existing files - const char ExtractArchiveCmd[] = R"(x -mmt=off "%s" -o"%s\*" -aos)"; - const char ExtractArchiveWithoutRootCmd[] = R"(x -mmt=off "%s" -o"%s" -aos)"; - const char AddFilesCmd[] = R"(a -tzip "%s" @"%s")"; - const char AddFileCmd[] = R"(a -tzip "%s" "%s")"; - const char ExtractFileCmd[] = R"(e -mmt=off "%s" "%s" %s)"; - const char ExtractFileDestination[] = R"(e -mmt=off "%s" -o"%s" "%s" %s)"; - const char ExtractOverwrite[] = "-aoa"; - const char ExtractSkipExisting[] = "-aos"; - const char ListFilesInArchiveCmd[] = R"(l -r -slt "%s")"; - - AZStd::string Get7zExePath() - { - const char* rootPath = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(rootPath, &AZ::ComponentApplicationRequests::GetEngineRoot); - AZStd::string exePath; - AzFramework::StringFunc::Path::ConstructFull(rootPath, "Tools", "7za", ".exe", exePath); - return exePath; - } - - AZStd::string GetZipExePath() - { - return Get7zExePath(); - } - - AZStd::string GetUnzipExePath() - { - return Get7zExePath(); - } - - AZStd::string GetCreateArchiveCommand(const AZStd::string& archivePath, const AZStd::string& dirToArchive) - { - return AZStd::string::format(CreateArchiveCmd, archivePath.c_str(), dirToArchive.c_str()); - } - - AZStd::string GetExtractArchiveCommand(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool includeRoot) - { - if (includeRoot) - { - // Extract archive path to destinationPath\ and skipping extracting of existing files - return AZStd::string::format(ExtractArchiveCmd, archivePath.c_str(), destinationPath.c_str()); - } - else - { - // Extract archive path to destinationPath and skipping extracting of existing files - return AZStd::string::format(ExtractArchiveWithoutRootCmd, archivePath.c_str(), destinationPath.c_str()); - } - } - - AZStd::string GetAddFilesToArchiveCommand(const AZStd::string& archivePath, const AZStd::string& listFilePath) - { - return AZStd::string::format(AddFilesCmd, archivePath.c_str(), listFilePath.c_str()); - } - - AZStd::string GetAddFileToArchiveCommand(const AZStd::string& archivePath, const AZStd::string& file) - { - return AZStd::string::format(AddFileCmd, archivePath.c_str(), file.c_str()); - } - - AZStd::string GetExtractFileCommand(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite) - { - AZStd::string commandLineArgs; - if (destinationPath.empty()) - { - // Extract file in archive from archive path to the current directory, overwriting a file of the same name that exists there. - commandLineArgs = AZStd::string::format(ExtractFileCmd, archivePath.c_str(), fileInArchive.c_str(), overWrite ? ExtractOverwrite : ExtractSkipExisting); - } - else - { - // Extract file in archive from archive path to destinationPath, overwriting a file of the same name that exists there. - commandLineArgs = AZStd::string::format(ExtractFileDestination, archivePath.c_str(), destinationPath.c_str(), fileInArchive.c_str(), overWrite ? ExtractOverwrite : ExtractSkipExisting); - } - - return commandLineArgs; - } - - AZStd::string GetListFilesInArchiveCommand(const AZStd::string& archivePath) - { - AZStd::string commandLineArgs = AZStd::string::format(ListFilesInArchiveCmd, archivePath.c_str()); - return commandLineArgs; - } - - /* - File output for our list archive commands takes the following two patterns for files vs directories: - - Path = basicfile2.txt - Folder = - - Size = 1 - Packed Size = 1 - Modified = 2019-03-26 18:31:10 - Created = 2019-03-26 18:31:10 - Accessed = 2019-03-26 18:31:10 - Attributes = A - Encrypted = - - Comment = - CRC = 32D70693 - Method = Store - Characteristics = NTFS - Host OS = FAT - Version = 10 - Volume Index = 0 - Offset = 44 - - Path = testfolder - Folder = + - Size = 0 - Packed Size = 0 - Modified = 2019-03-26 18:31:10 - Created = 2019-03-26 18:31:10 - Accessed = 2019-03-26 18:31:10 - Attributes = D - Encrypted = - - Comment = - CRC = - Method = Store - Characteristics = NTFS - Host OS = FAT - Version = 20 - Volume Index = 0 - Offset = 89 - - */ - - void ParseConsoleOutputFromListFilesInArchive(const AZStd::string& consoleOutput, AZStd::vector& fileEntries) - { - AZStd::vector fileEntryData; - AzFramework::StringFunc::Tokenize(consoleOutput.c_str(), fileEntryData, "\r\n"); - for (size_t slotNum = 0; slotNum < fileEntryData.size(); ++slotNum) - { - AZStd::string& line = fileEntryData[slotNum]; - if (AzFramework::StringFunc::StartsWith(line, "Path = ")) - { - if ((slotNum + 1) < fileEntryData.size()) - { - // We're checking one past each entry we find for the Folder entry and skipping anything marked as a folder - // See sample output above - if (AzFramework::StringFunc::StartsWith(fileEntryData[slotNum + 1], "Folder = -")) - { - AzFramework::StringFunc::Replace(line, "Path = ", "", false, true); - fileEntries.emplace_back(AZStd::move(line)); - slotNum++; - } - } - } - } - } - } // namespace Platform -} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/Platform/Windows/platform_windows_files.cmake b/Code/Framework/AzToolsFramework/Platform/Windows/platform_windows_files.cmake index d4fc29984c..c2c5a11c4c 100644 --- a/Code/Framework/AzToolsFramework/Platform/Windows/platform_windows_files.cmake +++ b/Code/Framework/AzToolsFramework/Platform/Windows/platform_windows_files.cmake @@ -7,5 +7,4 @@ # set(FILES - AzToolsFramework/Archive/ArchiveComponent_Windows.cpp ) diff --git a/Code/Framework/AzToolsFramework/Tests/ArchiveTests.cpp b/Code/Framework/AzToolsFramework/Tests/ArchiveTests.cpp index e7dad4b72f..66520c804c 100644 --- a/Code/Framework/AzToolsFramework/Tests/ArchiveTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/ArchiveTests.cpp @@ -31,7 +31,6 @@ namespace UnitTest { namespace { - bool CreateDummyFile(const QString& fullPathToFile, const QString& tempStr = {}) { QFileInfo fi(fullPathToFile); @@ -50,7 +49,7 @@ namespace UnitTest return true; } - class ArchiveTest : + class ArchiveComponentTest : public ::testing::Test { @@ -73,7 +72,12 @@ namespace UnitTest return "Archive"; } - void CreateArchiveFolder( QString archiveFolderName, QStringList fileList ) + QString GetExtractFolderName() + { + return "Extracted"; + } + + void CreateArchiveFolder(QString archiveFolderName, QStringList fileList) { QDir tempPath = QDir(m_tempDir.GetDirectory()).filePath(archiveFolderName); @@ -84,6 +88,14 @@ namespace UnitTest } } + QString CreateArchiveListTextFile() + { + QString listFilePath = QDir(m_tempDir.GetDirectory()).absoluteFilePath("FileList.txt"); + QString textContent = CreateArchiveFileList().join("\n"); + EXPECT_TRUE(CreateDummyFile(listFilePath, textContent)); + return listFilePath; + } + void CreateArchiveFolder() { CreateArchiveFolder(GetArchiveFolderName(), CreateArchiveFileList()); @@ -99,16 +111,24 @@ namespace UnitTest return QDir(m_tempDir.GetDirectory()).filePath(GetArchiveFolderName()); } + QString GetExtractFolder() + { + return QDir(m_tempDir.GetDirectory()).filePath(GetExtractFolderName()); + } + bool CreateArchive() { - bool createResult{ false }; - AzToolsFramework::ArchiveCommandsBus::BroadcastResult(createResult, &AzToolsFramework::ArchiveCommandsBus::Events::CreateArchiveBlocking, GetArchivePath().toStdString().c_str(), GetArchiveFolder().toStdString().c_str()); - return createResult; + std::future createResult; + AzToolsFramework::ArchiveCommandsBus::BroadcastResult(createResult, + &AzToolsFramework::ArchiveCommandsBus::Events::CreateArchive, + GetArchivePath().toUtf8().constData(), GetArchiveFolder().toUtf8().constData()); + bool result = createResult.get(); + return result; } void SetUp() override { - m_app.reset(aznew ToolsTestApplication("ArchiveTest")); + m_app.reset(aznew ToolsTestApplication("ArchiveComponentTest")); m_app->Start(AzFramework::Application::Descriptor()); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash @@ -132,76 +152,138 @@ namespace UnitTest }; #if AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS - TEST_F(ArchiveTest, DISABLED_CreateArchiveBlocking_FilesAtThreeDepths_ArchiveCreated) + TEST_F(ArchiveComponentTest, DISABLED_CreateArchive_FilesAtThreeDepths_ArchiveCreated) #else - TEST_F(ArchiveTest, CreateArchiveBlocking_FilesAtThreeDepths_ArchiveCreated) + TEST_F(ArchiveComponentTest, CreateArchive_FilesAtThreeDepths_ArchiveCreated) #endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS { EXPECT_TRUE(m_tempDir.IsValid()); CreateArchiveFolder(); + AZ_TEST_START_TRACE_SUPPRESSION; bool createResult = CreateArchive(); + AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; - EXPECT_EQ(createResult, true); + EXPECT_TRUE(createResult); } #if AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS - TEST_F(ArchiveTest, DISABLED_ListFilesInArchiveBlocking_FilesAtThreeDepths_FilesFound) + TEST_F(ArchiveComponentTest, DISABLED_ListFilesInArchive_FilesAtThreeDepths_FilesFound) #else - TEST_F(ArchiveTest, ListFilesInArchiveBlocking_FilesAtThreeDepths_FilesFound) + TEST_F(ArchiveComponentTest, ListFilesInArchive_FilesAtThreeDepths_FilesFound) #endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS { EXPECT_TRUE(m_tempDir.IsValid()); CreateArchiveFolder(); - + + AZ_TEST_START_TRACE_SUPPRESSION; EXPECT_EQ(CreateArchive(), true); AZStd::vector fileList; bool listResult{ false }; - AzToolsFramework::ArchiveCommandsBus::BroadcastResult(listResult, &AzToolsFramework::ArchiveCommandsBus::Events::ListFilesInArchiveBlocking, GetArchivePath().toStdString().c_str(), fileList); + AzToolsFramework::ArchiveCommandsBus::BroadcastResult(listResult, + &AzToolsFramework::ArchiveCommandsBus::Events::ListFilesInArchive, + GetArchivePath().toUtf8().constData(), fileList); + AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; + EXPECT_TRUE(listResult); EXPECT_EQ(fileList.size(), 6); } #if AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS - TEST_F(ArchiveTest, DISABLED_CreateDeltaCatalog_AssetsNotRegistered_Failure) + TEST_F(ArchiveComponentTest, DISABLED_CreateDeltaCatalog_AssetsNotRegistered_Failure) #else - TEST_F(ArchiveTest, CreateDeltaCatalog_AssetsNotRegistered_Failure) + TEST_F(ArchiveComponentTest, CreateDeltaCatalog_AssetsNotRegistered_Failure) #endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS { QStringList fileList = CreateArchiveFileList(); CreateArchiveFolder(GetArchiveFolderName(), fileList); - + AZ_TEST_START_TRACE_SUPPRESSION; bool createResult = CreateArchive(); + AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; EXPECT_EQ(createResult, true); bool catalogCreated{ true }; AZ::Test::AssertAbsorber assertAbsorber; - AzToolsFramework::AssetBundleCommandsBus::BroadcastResult(catalogCreated, &AzToolsFramework::AssetBundleCommandsBus::Events::CreateDeltaCatalog, GetArchivePath().toStdString().c_str(), true); + AzToolsFramework::AssetBundleCommandsBus::BroadcastResult(catalogCreated, + &AzToolsFramework::AssetBundleCommandsBus::Events::CreateDeltaCatalog, GetArchivePath().toUtf8().constData(), true); EXPECT_EQ(catalogCreated, false); } #if AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS - TEST_F(ArchiveTest, DISABLED_CreateDeltaCatalog_ArchiveWithoutCatalogAssetsRegistered_Success) + TEST_F(ArchiveComponentTest, DISABLED_AddFilesToArchive_FromListFile_Success) #else - TEST_F(ArchiveTest, CreateDeltaCatalog_ArchiveWithoutCatalogAssetsRegistered_Success) + TEST_F(ArchiveComponentTest, AddFilesToArchive_FromListFile_Success) +#endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS + { + QString listFile = CreateArchiveListTextFile(); + CreateArchiveFolder(GetArchiveFolderName(), CreateArchiveFileList()); + + AZ_TEST_START_TRACE_SUPPRESSION; + std::future addResult; + AzToolsFramework::ArchiveCommandsBus::BroadcastResult( + addResult, &AzToolsFramework::ArchiveCommandsBus::Events::AddFilesToArchive, GetArchivePath().toUtf8().constData(), + GetArchiveFolder().toUtf8().constData(), listFile.toUtf8().constData()); + bool result = addResult.get(); + AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; + + EXPECT_TRUE(result); + } + +#if AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS + TEST_F(ArchiveComponentTest, DISABLED_ExtractArchive_AllFiles_Success) +#else + TEST_F(ArchiveComponentTest, ExtractArchive_AllFiles_Success) +#endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS + { + CreateArchiveFolder(); + AZ_TEST_START_TRACE_SUPPRESSION; + bool createResult = CreateArchive(); + AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; + EXPECT_TRUE(createResult); + + AZ_TEST_START_TRACE_SUPPRESSION; + std::future extractResult; + AzToolsFramework::ArchiveCommandsBus::BroadcastResult( + extractResult, &AzToolsFramework::ArchiveCommandsBus::Events::ExtractArchive, GetArchivePath().toUtf8().constData(), + GetExtractFolder().toUtf8().constData()); + bool result = extractResult.get(); + AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; + + EXPECT_TRUE(result); + + QStringList archiveFiles = CreateArchiveFileList(); + for (const auto& file : archiveFiles) + { + QString fullFilePath = QDir(GetExtractFolder()).absoluteFilePath(file); + QFileInfo fi(fullFilePath); + EXPECT_TRUE(fi.exists()); + } + } + +#if AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS + TEST_F(ArchiveComponentTest, DISABLED_CreateDeltaCatalog_ArchiveWithoutCatalogAssetsRegistered_Success) +#else + TEST_F(ArchiveComponentTest, CreateDeltaCatalog_ArchiveWithoutCatalogAssetsRegistered_Success) #endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS { QStringList fileList = CreateArchiveFileList(); CreateArchiveFolder(GetArchiveFolderName(), fileList); + AZ_TEST_START_TRACE_SUPPRESSION; bool createResult = CreateArchive(); + AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; EXPECT_EQ(createResult, true); for (const auto& thisPath : fileList) { AZ::Data::AssetInfo newInfo; - newInfo.m_relativePath = thisPath.toStdString().c_str(); + newInfo.m_relativePath = thisPath.toUtf8().constData(); newInfo.m_assetType = AZ::Uuid::CreateRandom(); newInfo.m_sizeBytes = 100; // Arbitrary AZ::Data::AssetId generatedID(AZ::Uuid::CreateRandom()); @@ -212,7 +294,7 @@ namespace UnitTest bool catalogCreated{ false }; AZ_TEST_START_TRACE_SUPPRESSION; - AzToolsFramework::AssetBundleCommandsBus::BroadcastResult(catalogCreated, &AzToolsFramework::AssetBundleCommandsBus::Events::CreateDeltaCatalog, GetArchivePath().toStdString().c_str(), true); + AzToolsFramework::AssetBundleCommandsBus::BroadcastResult(catalogCreated, &AzToolsFramework::AssetBundleCommandsBus::Events::CreateDeltaCatalog, GetArchivePath().toUtf8().constData(), true); AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // produces different counts in different platforms EXPECT_EQ(catalogCreated, true); } diff --git a/Code/Framework/GridMate/GridMate/Carrier/Carrier.cpp b/Code/Framework/GridMate/GridMate/Carrier/Carrier.cpp index 095f392501..2922cc2891 100644 --- a/Code/Framework/GridMate/GridMate/Carrier/Carrier.cpp +++ b/Code/Framework/GridMate/GridMate/Carrier/Carrier.cpp @@ -1316,7 +1316,7 @@ CarrierThread::CarrierThread(const CarrierDesc& desc, AZStd::shared_ptrGetReadablePlatformList(seed).c_str()); m_additionalSeedInfoMap[seed.m_assetId].reset(new AdditionalSeedInfo(assetInfo.m_relativePath.c_str(), platformList)); diff --git a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp index eb6cc4033c..42a43ef84e 100644 --- a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp +++ b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp @@ -411,7 +411,7 @@ bool AssetBuilderComponent::RunInResidentMode() m_running = true; m_jobThreadDesc.m_name = "Builder Job Thread"; - m_jobThread = AZStd::thread(AZStd::bind(&AssetBuilderComponent::JobThread, this), &m_jobThreadDesc); + m_jobThread = AZStd::thread(m_jobThreadDesc, AZStd::bind(&AssetBuilderComponent::JobThread, this)); AzFramework::EngineConnectionEvents::Bus::Handler::BusConnect(); // Listen for disconnects diff --git a/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp b/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp index 4257457291..5d2d0e77d3 100644 --- a/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp @@ -1063,10 +1063,10 @@ namespace AssetProcessor AZStd::thread_desc threadDesc; threadDesc.m_name = "AssetCatalog Thread"; - AZStd::thread catalogThread([this]() + AZStd::thread catalogThread(threadDesc, [this]() { m_data->m_assetCatalog->BuildRegistry(); - }, &threadDesc + } ); AssetNotificationMessage message("some/path/image.png", AssetNotificationMessage::NotificationType::AssetChanged, AZ::Data::AssetType::CreateRandom(), "pc"); diff --git a/Code/Tools/AssetProcessor/native/utilities/AssetServerHandler.cpp b/Code/Tools/AssetProcessor/native/utilities/AssetServerHandler.cpp index 3d87c11488..3fa4b1cacd 100644 --- a/Code/Tools/AssetProcessor/native/utilities/AssetServerHandler.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/AssetServerHandler.cpp @@ -74,8 +74,11 @@ namespace AssetProcessor AZ_TracePrintf(AssetProcessor::DebugChannel, "Extracting archive for job (%s, %s, %s) with fingerprint (%u).\n", builderParams.m_rcJob->GetJobEntry().m_pathRelativeToWatchFolder.toUtf8().data(), builderParams.m_rcJob->GetJobKey().toUtf8().data(), builderParams.m_rcJob->GetPlatformInfo().m_identifier.c_str(), builderParams.m_rcJob->GetOriginalFingerprint()); - bool success = false; - AzToolsFramework::ArchiveCommands::Bus::BroadcastResult(success, &AzToolsFramework::ArchiveCommands::ExtractArchiveBlocking, archiveAbsFilePath.toUtf8().data(), builderParams.GetTempJobDirectory(), false); + std::future extractResult; + AzToolsFramework::ArchiveCommandsBus::BroadcastResult(extractResult, + &AzToolsFramework::ArchiveCommandsBus::Events::ExtractArchive, + archiveAbsFilePath.toUtf8().data(), builderParams.GetTempJobDirectory()); + bool success = extractResult.get(); AZ_Error(AssetProcessor::DebugChannel, success, "Extracting archive operation failed.\n"); return success; } @@ -106,12 +109,15 @@ namespace AssetProcessor return false; } - bool success = false; - AZ_TracePrintf(AssetProcessor::DebugChannel, "Creating archive for job (%s, %s, %s) with fingerprint (%u).\n", builderParams.m_rcJob->GetJobEntry().m_pathRelativeToWatchFolder.toUtf8().data(), builderParams.m_rcJob->GetJobKey().toUtf8().data(), builderParams.m_rcJob->GetPlatformInfo().m_identifier.c_str(), builderParams.m_rcJob->GetOriginalFingerprint()); - AzToolsFramework::ArchiveCommands::Bus::BroadcastResult(success, &AzToolsFramework::ArchiveCommands::CreateArchiveBlocking, archiveAbsFilePath.toUtf8().data(), builderParams.GetTempJobDirectory()); + + std::future createResult; + AzToolsFramework::ArchiveCommandsBus::BroadcastResult(createResult, + &AzToolsFramework::ArchiveCommandsBus::Events::CreateArchive, + archiveAbsFilePath.toUtf8().data(), builderParams.GetTempJobDirectory()); + bool success = createResult.get(); AZ_Error(AssetProcessor::DebugChannel, success, "Creating archive operation failed. \n"); if (success && sourceFileList.size()) @@ -137,14 +143,16 @@ namespace AssetProcessor allSuccess = false; continue; } - bool success{ false }; - AzToolsFramework::ArchiveCommands::Bus::BroadcastResult(success, &AzToolsFramework::ArchiveCommands::AddFileToArchiveBlocking, archivePath.toUtf8().data(), sourceDir.path().toUtf8().data(), thisProduct.c_str()); + std::future addResult; + AzToolsFramework::ArchiveCommandsBus::BroadcastResult(addResult, + &AzToolsFramework::ArchiveCommandsBus::Events::AddFileToArchive, + archivePath.toUtf8().data(), sourceDir.path().toUtf8().data(), thisProduct.c_str()); + bool success = addResult.get(); if (!success) { AZ_Warning(AssetProcessor::DebugChannel, false, "Failed to add %s to %s", thisProduct.c_str(), archivePath.toUtf8().data()); allSuccess = false; } - } return allSuccess; } diff --git a/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp b/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp index 0a8d9d8eb7..f0c1d765e5 100644 --- a/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp +++ b/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp @@ -99,7 +99,7 @@ void SRemoteThreadedObject::Start(const char* name) desc.m_name = name; auto function = AZStd::bind(&SRemoteThreadedObject::ThreadFunction, this); - m_thread = AZStd::thread(function, &desc); + m_thread = AZStd::thread(desc, function); } void SRemoteThreadedObject::WaitForThread() diff --git a/Gems/Atom/RHI/Code/Source/RHI/AsyncWorkQueue.cpp b/Gems/Atom/RHI/Code/Source/RHI/AsyncWorkQueue.cpp index a076bf3e58..61f05306be 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/AsyncWorkQueue.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/AsyncWorkQueue.cpp @@ -26,7 +26,7 @@ namespace AZ m_workItemIndex = 0; m_lastCompletedWorkItem = AsyncWorkHandle::Null; AZStd::thread_desc threadDesc{ "AsyncWorkQueue" }; - m_thread = AZStd::thread([&]() { ProcessQueue(); }, &threadDesc); + m_thread = AZStd::thread(threadDesc, [&]() { ProcessQueue(); }); m_isInitialized = true; } diff --git a/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp b/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp index b50c36d3f9..f65c36f2ed 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp @@ -43,7 +43,7 @@ namespace AZ m_isWorkQueueEmpty = true; AZStd::thread_desc threadDesc{ GetName().GetCStr() }; - m_thread = AZStd::thread([&]() { ProcessQueue(); }, &threadDesc); + m_thread = AZStd::thread(threadDesc, [&]() { ProcessQueue(); }); } return resultCode; } diff --git a/Gems/Atom/RHI/Code/Source/RHI/Fence.cpp b/Gems/Atom/RHI/Code/Source/RHI/Fence.cpp index d030ff8d2b..162b07406e 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/Fence.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/Fence.cpp @@ -108,7 +108,7 @@ namespace AZ AZStd::thread_desc threadDesc{ "Fence WaitOnCpu Thread" }; - m_waitThread = AZStd::thread([this, callback]() + m_waitThread = AZStd::thread(threadDesc, [this, callback]() { ResultCode resultCode = WaitOnCpu(); if (resultCode != ResultCode::Success) @@ -116,7 +116,7 @@ namespace AZ AZ_Error("Fence", false, "Failed to call WaitOnCpu in async thread."); } callback(); - }, &threadDesc); + }); return ResultCode::Success; } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariantAsyncLoader.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariantAsyncLoader.cpp index 4855fbd864..36109b7b82 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariantAsyncLoader.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariantAsyncLoader.cpp @@ -24,12 +24,11 @@ namespace AZ threadDesc.m_name = "ShaderVariantAsyncLoader"; m_serviceThread = AZStd::thread( + threadDesc, [this]() { this->ThreadServiceLoop(); - }, - &threadDesc - ); + }); } void ShaderVariantAsyncLoader::ThreadServiceLoop() diff --git a/Gems/AudioSystem/Code/Source/Engine/AudioSystem.cpp b/Gems/AudioSystem/Code/Source/Engine/AudioSystem.cpp index 5f3603c956..67c5325be9 100644 --- a/Gems/AudioSystem/Code/Source/Engine/AudioSystem.cpp +++ b/Gems/AudioSystem/Code/Source/Engine/AudioSystem.cpp @@ -56,7 +56,7 @@ namespace Audio threadDesc.m_cpuId = AZ_TRAIT_AUDIOSYSTEM_AUDIO_THREAD_AFFINITY; auto threadFunc = AZStd::bind(&CAudioThread::Run, this); - m_thread = AZStd::thread(threadFunc, &threadDesc); + m_thread = AZStd::thread(threadDesc, threadFunc); } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Gems/BarrierInput/Code/Source/BarrierInputClient.cpp b/Gems/BarrierInput/Code/Source/BarrierInputClient.cpp index e6d5399561..ec4cbcfbd1 100644 --- a/Gems/BarrierInput/Code/Source/BarrierInputClient.cpp +++ b/Gems/BarrierInput/Code/Source/BarrierInputClient.cpp @@ -347,7 +347,7 @@ namespace BarrierInput { AZStd::thread_desc threadDesc; threadDesc.m_name = "BarrierInputClientThread"; - m_threadHandle = AZStd::thread(AZStd::bind(&BarrierClient::Run, this), &threadDesc); + m_threadHandle = AZStd::thread(threadDesc, AZStd::bind(&BarrierClient::Run, this)); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Gems/HttpRequestor/Code/Source/HttpRequestManager.cpp b/Gems/HttpRequestor/Code/Source/HttpRequestManager.cpp index d33f37a2d7..06cf018f76 100644 --- a/Gems/HttpRequestor/Code/Source/HttpRequestManager.cpp +++ b/Gems/HttpRequestor/Code/Source/HttpRequestManager.cpp @@ -37,7 +37,7 @@ namespace HttpRequestor m_runThread = true; AWSNativeSDKInit::InitializationManager::InitAwsApi(); auto function = AZStd::bind(&Manager::ThreadFunction, this); - m_thread = AZStd::thread(function, &desc); + m_thread = AZStd::thread(desc, function); } Manager::~Manager() diff --git a/Gems/LmbrCentral/Code/Source/Builders/LevelBuilder/LevelBuilderWorker.cpp b/Gems/LmbrCentral/Code/Source/Builders/LevelBuilder/LevelBuilderWorker.cpp index 95a908b20c..631bc41358 100644 --- a/Gems/LmbrCentral/Code/Source/Builders/LevelBuilder/LevelBuilderWorker.cpp +++ b/Gems/LmbrCentral/Code/Source/Builders/LevelBuilder/LevelBuilderWorker.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -155,35 +156,17 @@ namespace LevelBuilder { PopulateOptionalLevelDependencies(sourceRelativeFile, productPathDependencies); - AZStd::binary_semaphore extractionCompleteSemaphore; - auto extractResponseLambda = [&]([[maybe_unused]] bool success) { - AZStd::string levelsubfolder; - AzFramework::StringFunc::Path::Join(tempDirectory.c_str(), "level", levelsubfolder); + std::future extractResult; + AzToolsFramework::ArchiveCommandsBus::BroadcastResult( + extractResult, &AzToolsFramework::ArchiveCommandsBus::Events::ExtractArchive, levelPakFile, tempDirectory); - PopulateLevelSliceDependencies(levelsubfolder, productDependencies, productPathDependencies); - PopulateMissionDependencies(levelPakFile, levelsubfolder, productPathDependencies); - PopulateLevelAudioControlDependencies(levelPakFile, productPathDependencies); + extractResult.wait(); - extractionCompleteSemaphore.release(); - }; + auto levelsubfolder = AZ::IO::Path(tempDirectory) / "level"; - AZ::Uuid handle = AZ::Uuid::Create(); - AzToolsFramework::ArchiveCommands::Bus::Broadcast( - &AzToolsFramework::ArchiveCommands::ExtractArchive, - levelPakFile, - tempDirectory, - handle, - extractResponseLambda); - - const int archiveExtractSleepMS = 20; - bool extractionCompleted = false; - while (!extractionCompleted) - { - extractionCompleted = extractionCompleteSemaphore.try_acquire_for(AZStd::chrono::milliseconds(archiveExtractSleepMS)); - // When the archive extraction is completed, the response lambda is queued on the the tick bus. - // This loop will keep executing queued events on the tickbus until the response unlocks the semaphore. - AZ::TickBus::ExecuteQueuedEvents(); - } + PopulateLevelSliceDependencies(levelsubfolder.Native(), productDependencies, productPathDependencies); + PopulateMissionDependencies(levelPakFile, levelsubfolder.Native(), productPathDependencies); + PopulateLevelAudioControlDependencies(levelPakFile, productPathDependencies); } AZStd::string GetLastFolderFromPath(const AZStd::string& path) diff --git a/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp b/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp index c182ec4f3b..e0b1f1ae36 100644 --- a/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp +++ b/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp @@ -225,7 +225,7 @@ namespace Audio AZStd::thread_desc threadDesc; threadDesc.m_name = "MicrophoneCapture-WASAPI"; auto captureFunc = AZStd::bind(&MicrophoneSystemComponentWindows::RunAudioCapture, this); - m_captureThread = AZStd::thread(captureFunc, &threadDesc); + m_captureThread = AZStd::thread(threadDesc, captureFunc); return true; } diff --git a/Gems/PhysX/Code/Tests/PhysXMultithreadingTest.cpp b/Gems/PhysX/Code/Tests/PhysXMultithreadingTest.cpp index a0013402b1..205ad4f377 100644 --- a/Gems/PhysX/Code/Tests/PhysXMultithreadingTest.cpp +++ b/Gems/PhysX/Code/Tests/PhysXMultithreadingTest.cpp @@ -119,7 +119,7 @@ namespace PhysX void Start(int waitTimeMilliseconds) { m_waitTimeMilliseconds = waitTimeMilliseconds; - m_thread = AZStd::thread(AZStd::bind(&SceneQueryBase::Tick, this), &m_threadDesc); + m_thread = AZStd::thread(m_threadDesc, AZStd::bind(&SceneQueryBase::Tick, this)); } void Join() diff --git a/Gems/SaveData/Code/Source/SaveDataSystemComponent.cpp b/Gems/SaveData/Code/Source/SaveDataSystemComponent.cpp index dad6e24abc..e92df0da68 100644 --- a/Gems/SaveData/Code/Source/SaveDataSystemComponent.cpp +++ b/Gems/SaveData/Code/Source/SaveDataSystemComponent.cpp @@ -172,14 +172,15 @@ namespace SaveData // This is safe access outside the lock guard because we only remove elements from the list // after the thread completion flag has been set to true (see also JoinAllCompletedThreads). - threadCompletionPair->m_thread = AZStd::make_unique([&threadCompleteFlag = threadCompletionPair->m_threadComplete, - dataBuffer = AZStd::move(saveDataBufferParams.dataBuffer), - dataBufferSize = saveDataBufferParams.dataBufferSize, - dataBufferName = saveDataBufferParams.dataBufferName, - onSavedCallback = saveDataBufferParams.callback, - localUserId = saveDataBufferParams.localUserId, - absoluteFilePath, - useTemporaryFile]() + threadCompletionPair->m_thread = AZStd::make_unique(saveThreadDesc, + [&threadCompleteFlag = threadCompletionPair->m_threadComplete, + dataBuffer = AZStd::move(saveDataBufferParams.dataBuffer), + dataBufferSize = saveDataBufferParams.dataBufferSize, + dataBufferName = saveDataBufferParams.dataBufferName, + onSavedCallback = saveDataBufferParams.callback, + localUserId = saveDataBufferParams.localUserId, + absoluteFilePath, + useTemporaryFile]() { SaveDataNotifications::Result result = SaveDataNotifications::Result::ErrorUnspecified; @@ -234,7 +235,7 @@ namespace SaveData // Set the thread completion flag so it will be joined in JoinAllCompletedThreads. threadCompleteFlag = true; - }, &saveThreadDesc); + }); if (waitForCompletion) { @@ -301,9 +302,10 @@ namespace SaveData // This is safe access outside the lock guard because we only remove elements from the list // after the thread completion flag has been set to true (see also JoinAllCompletedThreads). - threadCompletionPair->m_thread = AZStd::make_unique([&threadCompleteFlag = threadCompletionPair->m_threadComplete, - loadDataBufferParams, - absoluteFilePath]() + threadCompletionPair->m_thread = AZStd::make_unique(loadThreadDesc, + [&threadCompleteFlag = threadCompletionPair->m_threadComplete, + loadDataBufferParams, + absoluteFilePath]() { SaveDataNotifications::DataBuffer dataBuffer = nullptr; AZ::u64 dataBufferSize = 0; @@ -352,7 +354,7 @@ namespace SaveData // Set the thread completion flag so it will be joined in JoinAllCompletedThreads. threadCompleteFlag = true; - }, &loadThreadDesc); + }); if (waitForCompletion) { diff --git a/Tools/7za.exe b/Tools/7za.exe deleted file mode 100644 index 8a7a9ab6fb..0000000000 --- a/Tools/7za.exe +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:77613cca716edf68b9d5bab951463ed7fade5bc0ec465b36190a76299c50f117 -size 733696 diff --git a/Tools/7za_legal_notice.txt b/Tools/7za_legal_notice.txt deleted file mode 100644 index 6bcdfb1e31..0000000000 --- a/Tools/7za_legal_notice.txt +++ /dev/null @@ -1,36 +0,0 @@ -Amazon note: Source for 7-zip is hosted at -https://s3-us-west-2.amazonaws.com/ly-legal/LicenseConformance/7-zip/18.05/7z1805-src.7z - - - - 7-Zip Extra - ~~~~~~~~~~~ - License for use and distribution - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Copyright (C) 1999-2015 Igor Pavlov. - - 7-Zip Extra files are under the GNU LGPL license. - - - Notes: - You can use 7-Zip Extra on any computer, including a computer in a commercial - organization. You don't need to register or pay for 7-Zip. - - - GNU LGPL information - -------------------- - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You can receive a copy of the GNU Lesser General Public License from - http://www.gnu.org/ - From c245960c7b32b463c9b197fd6af103003f0a674b Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Fri, 1 Oct 2021 10:17:08 -0500 Subject: [PATCH 43/50] remove addition of the LoggerService as a required service Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp b/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp index 8c78ff0e73..2567d221e5 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp @@ -56,7 +56,6 @@ namespace AZ void RPISystemComponent::GetRequiredServices(ComponentDescriptor::DependencyArrayType& required) { required.push_back(RHI::Factory::GetComponentService()); - required.push_back(AZ_CRC_CE("LoggerService")); } void RPISystemComponent::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) From bf393ec85c62129de801d0e65d5a968bb99d0133 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 1 Oct 2021 08:38:46 -0700 Subject: [PATCH 44/50] fixes some install paths issues in monolithic release (#4422) * fixes some install paths issues in monolithic release Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * PR comments Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/LauncherUnified/launcher_generator.cmake | 17 ++--- Code/Legacy/CryCommon/ProjectDefines.h | 3 - Code/Legacy/CryCommon/platform_impl.cpp | 3 - Registry/CMakeLists.txt | 4 +- cmake/Packaging.cmake | 70 +++++++++++-------- cmake/Platform/Common/Install_common.cmake | 15 ++++ .../Platform/Windows/Packaging_windows.cmake | 1 + cmake/Projects.cmake | 20 ++++-- 8 files changed, 76 insertions(+), 57 deletions(-) diff --git a/Code/LauncherUnified/launcher_generator.cmake b/Code/LauncherUnified/launcher_generator.cmake index b30f752c85..5c9ee68e27 100644 --- a/Code/LauncherUnified/launcher_generator.cmake +++ b/Code/LauncherUnified/launcher_generator.cmake @@ -19,19 +19,10 @@ foreach(project_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJEC # Otherwise the the absolute project_path is returned with symlinks resolved file(REAL_PATH ${project_path} project_real_path BASE_DIRECTORY ${LY_ROOT_FOLDER}) if(NOT project_name) - if(NOT EXISTS ${project_real_path}/project.json) - message(FATAL_ERROR "The specified project path of ${project_real_path} does not contain a project.json file") - else() - # Add the project_name to global LY_PROJECTS_TARGET_NAME property - ly_file_read("${project_real_path}/project.json" project_json) - string(JSON project_name ERROR_VARIABLE json_error GET ${project_json} "project_name") - if(json_error) - message(FATAL_ERROR "There is an error reading the \"project_name\" key from the '${project_real_path}/project.json' file: ${json_error}") - endif() - message(WARNING "The project located at path ${project_real_path} has a valid \"project name\" of '${project_name}' read from it's project.json file." - " This indicates that the ${project_real_path}/CMakeLists.txt is not properly appending the \"project name\" " - "to the LY_PROJECTS_TARGET_NAME global property. Other configuration errors might occur") - endif() + o3de_read_json_key(project_name ${project_real_path}/project.json "project_name") + message(WARNING "The project located at path ${project_real_path} has a valid \"project name\" of '${project_name}' read from it's project.json file." + " This indicates that the ${project_real_path}/CMakeLists.txt is not properly appending the \"project name\" " + "to the LY_PROJECTS_TARGET_NAME global property. Other configuration errors might occur") endif() ################################################################################ diff --git a/Code/Legacy/CryCommon/ProjectDefines.h b/Code/Legacy/CryCommon/ProjectDefines.h index 203bd304c9..2c3df4e37f 100644 --- a/Code/Legacy/CryCommon/ProjectDefines.h +++ b/Code/Legacy/CryCommon/ProjectDefines.h @@ -81,9 +81,6 @@ #include AZ_RESTRICTED_FILE(ProjectDefines_h) #else #define PROJECTDEFINES_H_TRAIT_DISABLE_MONOLITHIC_PROFILING_MARKERS 1 - #if !defined(LINUX) && !defined(APPLE) - #define PROJECTDEFINES_H_TRAIT_ENABLE_SOFTCODE_SYSTEM 1 - #endif #if defined(WIN32) || defined(WIN64) || defined(LINUX) || defined(APPLE) #define PROJECTDEFINES_H_TRAIT_USE_GPU_PARTICLES 1 #endif diff --git a/Code/Legacy/CryCommon/platform_impl.cpp b/Code/Legacy/CryCommon/platform_impl.cpp index 323d3daf65..a68a5150db 100644 --- a/Code/Legacy/CryCommon/platform_impl.cpp +++ b/Code/Legacy/CryCommon/platform_impl.cpp @@ -71,7 +71,6 @@ void InitCRTHandlers() void InitCRTHandlers() {} #endif -#ifndef SOFTCODE ////////////////////////////////////////////////////////////////////////// // This is an entry to DLL initialization function that must be called for each loaded module ////////////////////////////////////////////////////////////////////////// @@ -136,8 +135,6 @@ void* GetDetachEnvironmentSymbol() return reinterpret_cast(&DetachEnvironment); } -#endif // !defined(SOFTCODE) - bool g_bProfilerEnabled = false; ////////////////////////////////////////////////////////////////////////// diff --git a/Registry/CMakeLists.txt b/Registry/CMakeLists.txt index 100867010d..773adac07f 100644 --- a/Registry/CMakeLists.txt +++ b/Registry/CMakeLists.txt @@ -12,8 +12,6 @@ endif() ly_install_directory(DIRECTORIES .) -cmake_path(RELATIVE_PATH CMAKE_RUNTIME_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE runtime_output_directory) - ly_install_directory(DIRECTORIES ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/Registry - DESTINATION ${runtime_output_directory}/${PAL_PLATFORM_NAME}/$ + DESTINATION ${runtime_output_directory} ) diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index 477a5f24ea..006689549b 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -89,37 +89,49 @@ endif() set(_cmake_package_dest ${CPACK_BINARY_DIR}/${CPACK_CMAKE_PACKAGE_FILE}) -string(REPLACE "." ";" _version_componets "${CPACK_DESIRED_CMAKE_VERSION}") -list(GET _version_componets 0 _major_version) -list(GET _version_componets 1 _minor_version) - -set(_url_version_tag "v${_major_version}.${_minor_version}") -set(_package_url "https://cmake.org/files/${_url_version_tag}/${CPACK_CMAKE_PACKAGE_FILE}") - -message(STATUS "Downloading CMake ${CPACK_DESIRED_CMAKE_VERSION} for packaging...") -download_file( - URL ${_package_url} - TARGET_FILE ${_cmake_package_dest} - EXPECTED_HASH ${CPACK_CMAKE_PACKAGE_HASH} - RESULTS _results -) -list(GET _results 0 _status_code) - -if (${_status_code} EQUAL 0 AND EXISTS ${_cmake_package_dest}) - message(STATUS "Package found and verified!") -else() - file(REMOVE ${_cmake_package_dest}) - list(REMOVE_AT _results 0) - - set(_error_message "An error occurred, code ${_status_code}. URL ${_package_url} - ${_results}") - - if(${_status_code} EQUAL 1) - string(APPEND _error_message - " Please double check the CPACK_CMAKE_PACKAGE_FILE and " - "CPACK_CMAKE_PACKAGE_HASH properties before trying again.") +if(EXISTS ${_cmake_package_dest}) + file(SHA256 ${_cmake_package_dest} hash_of_downloaded_file) + if (NOT "${hash_of_downloaded_file}" STREQUAL "${CPACK_CMAKE_PACKAGE_HASH}") + message(STATUS "CMake ${CPACK_DESIRED_CMAKE_VERSION} found at ${_cmake_package_dest} but expected hash missmatches, re-downloading...") + file(REMOVE ${_cmake_package_dest}) + else() + message(STATUS "CMake ${CPACK_DESIRED_CMAKE_VERSION} found") endif() +endif() +if(NOT EXISTS ${_cmake_package_dest}) + # download it + string(REPLACE "." ";" _version_componets "${CPACK_DESIRED_CMAKE_VERSION}") + list(GET _version_componets 0 _major_version) + list(GET _version_componets 1 _minor_version) - message(FATAL_ERROR ${_error_message}) + set(_url_version_tag "v${_major_version}.${_minor_version}") + set(_package_url "https://cmake.org/files/${_url_version_tag}/${CPACK_CMAKE_PACKAGE_FILE}") + + message(STATUS "Downloading CMake ${CPACK_DESIRED_CMAKE_VERSION} for packaging...") + download_file( + URL ${_package_url} + TARGET_FILE ${_cmake_package_dest} + EXPECTED_HASH ${CPACK_CMAKE_PACKAGE_HASH} + RESULTS _results + ) + list(GET _results 0 _status_code) + + if (${_status_code} EQUAL 0 AND EXISTS ${_cmake_package_dest}) + message(STATUS "CMake ${CPACK_DESIRED_CMAKE_VERSION} found") + else() + file(REMOVE ${_cmake_package_dest}) + list(REMOVE_AT _results 0) + + set(_error_message "An error occurred, code ${_status_code}. URL ${_package_url} - ${_results}") + + if(${_status_code} EQUAL 1) + string(APPEND _error_message + " Please double check the CPACK_CMAKE_PACKAGE_FILE and " + "CPACK_CMAKE_PACKAGE_HASH properties before trying again.") + endif() + + message(FATAL_ERROR ${_error_message}) + endif() endif() install(FILES ${_cmake_package_dest} diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 8fb2effe29..5fa7f21939 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -430,6 +430,21 @@ function(ly_setup_cmake_install) DESTINATION . COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) + string(CONFIGURE [=[ +if("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$") + set(install_output_folder "${CMAKE_INSTALL_PREFIX}/@runtime_output_directory@") + file(WRITE ${install_output_folder}/engine.json +"{ + \"engine_name\": \"@LY_VERSION_ENGINE_NAME@\" +}") +endif() +]=] + install_engine_json_release + @ONLY + ) + install(CODE ${install_engine_json_release} + COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} # use the default for the time being + ) # Collect all Find files that were added with ly_add_external_target_path unset(additional_find_files) diff --git a/cmake/Platform/Windows/Packaging_windows.cmake b/cmake/Platform/Windows/Packaging_windows.cmake index ced7757852..4a03df2fd2 100644 --- a/cmake/Platform/Windows/Packaging_windows.cmake +++ b/cmake/Platform/Windows/Packaging_windows.cmake @@ -23,6 +23,7 @@ set(CPACK_WIX_ROOT ${LY_INSTALLER_WIX_ROOT}) set(CPACK_GENERATOR WIX) +set(CPACK_THREADS 0) set(_cmake_package_name "cmake-${CPACK_DESIRED_CMAKE_VERSION}-windows-x86_64") set(CPACK_CMAKE_PACKAGE_FILE "${_cmake_package_name}.zip") set(CPACK_CMAKE_PACKAGE_HASH "15a49e2ab81c1822d75b1b1a92f7863f58e31f6d6aac1c4103eef2b071be3112") diff --git a/cmake/Projects.cmake b/cmake/Projects.cmake index 61cb101909..b21704ee85 100644 --- a/cmake/Projects.cmake +++ b/cmake/Projects.cmake @@ -10,7 +10,7 @@ include_guard() -set(LY_PROJECTS "${LY_PROJECTS}" CACHE STRING "List of projects to enable, this can be a relative path to the engine root or an absolute path") +set(LY_PROJECTS "" CACHE STRING "List of projects to enable, this can be a relative path to the engine root or an absolute path") #! ly_add_target_dependencies: adds module load dependencies for this target. # @@ -143,21 +143,25 @@ foreach(project ${LY_PROJECTS}) ly_generate_project_build_path_setreg(${full_directory_path}) add_project_json_external_subdirectories(${full_directory_path}) + # Get project name + o3de_read_json_key(project_name ${full_directory_path}/project.json "project_name") + # Generate pak for project in release installs - cmake_path(RELATIVE_PATH CMAKE_RUNTIME_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE runtime_output_directory) + cmake_path(RELATIVE_PATH CMAKE_RUNTIME_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE install_base_runtime_output_directory) set(install_engine_pak_template [=[ if("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$") - set(install_output_folder "${CMAKE_INSTALL_PREFIX}/@runtime_output_directory@/@PAL_PLATFORM_NAME@/${CMAKE_INSTALL_CONFIG_NAME}/@LY_BUILD_PERMUTATION@") + set(install_output_folder "${CMAKE_INSTALL_PREFIX}/@install_base_runtime_output_directory@/@PAL_PLATFORM_NAME@/${CMAKE_INSTALL_CONFIG_NAME}/@LY_BUILD_PERMUTATION@") + set(install_pak_output_folder "${install_output_folder}/Cache/@LY_ASSET_DEPLOY_ASSET_TYPE@") if(NOT DEFINED LY_ASSET_DEPLOY_ASSET_TYPE) set(LY_ASSET_DEPLOY_ASSET_TYPE @LY_ASSET_DEPLOY_ASSET_TYPE@) endif() - message(STATUS "Generating ${install_output_folder}/engine.pak from @full_directory_path@/Cache/${LY_ASSET_DEPLOY_ASSET_TYPE}") - file(MAKE_DIRECTORY "${install_output_folder}") + message(STATUS "Generating ${install_pak_output_folder}/engine.pak from @full_directory_path@/Cache/${LY_ASSET_DEPLOY_ASSET_TYPE}") + file(MAKE_DIRECTORY "${install_pak_output_folder}") cmake_path(SET cache_product_path "@full_directory_path@/Cache/${LY_ASSET_DEPLOY_ASSET_TYPE}") file(GLOB product_assets "${cache_product_path}/*") if(product_assets) execute_process( - COMMAND ${CMAKE_COMMAND} -E tar "cf" "${install_output_folder}/engine.pak" --format=zip -- ${product_assets} + COMMAND ${CMAKE_COMMAND} -E tar "cf" "${install_pak_output_folder}/engine.pak" --format=zip -- ${product_assets} WORKING_DIRECTORY "${cache_product_path}" RESULT_VARIABLE archive_creation_result ) @@ -165,6 +169,10 @@ if("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$") message(STATUS "${install_output_folder}/engine.pak generated") endif() endif() + file(WRITE ${install_output_folder}/project.json +"{ + \"project_name\": \"@project_name@\" +}") endif() ]=]) string(CONFIGURE "${install_engine_pak_template}" install_engine_pak_code @ONLY) From b984335b302e55e67baf1f9ea3ce14dd7e238187 Mon Sep 17 00:00:00 2001 From: SJ Date: Fri, 1 Oct 2021 09:02:09 -0700 Subject: [PATCH 45/50] [Android] Fix black screen on Android when app is launched (#4418) * When copying the runtime dependency setreg files to the cache, the name of the registry directory should be all lower case Signed-off-by: amzn-sj * Lower case the registry folder name when looking in the asset cache. Signed-off-by: amzn-sj --- .../Settings/SettingsRegistryMergeUtils.cpp | 4 ++- .../Tools/Platform/Android/android_support.py | 26 +++++++++++++++---- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index da7110e36e..113fdd433e 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -717,7 +717,9 @@ namespace AZ::SettingsRegistryMergeUtils if (registry.Get(cacheRootPath, FilePathKey_CacheRootFolder)) { mergePath = AZStd::move(cacheRootPath); - mergePath /= SettingsRegistryInterface::RegistryFolder; + AZStd::fixed_string<32> registryFolderLower(SettingsRegistryInterface::RegistryFolder); + AZStd::to_lower(registryFolderLower.begin(), registryFolderLower.end()); + mergePath /= registryFolderLower; registry.MergeSettingsFolder(mergePath.Native(), specializations, platform, "", scratchBuffer); } diff --git a/cmake/Tools/Platform/Android/android_support.py b/cmake/Tools/Platform/Android/android_support.py index 77c8a37a35..54f1a4c8f4 100755 --- a/cmake/Tools/Platform/Android/android_support.py +++ b/cmake/Tools/Platform/Android/android_support.py @@ -381,6 +381,23 @@ CUSTOM_GRADLE_COPY_NATIVE_CONFIG_BUILD_ARTIFACTS_DEPENDENCY_FORMAT_STR = """ }} """ +CUSTOM_GRADLE_COPY_REGISTRY_FOLDER_FORMAT_STR = """ + task copyRegistryFolder{config}(type: Copy) {{ + from ('build/intermediates/cmake/{config_lower}/obj/arm64-v8a/{config_lower}/Registry') + into ('{asset_layout_folder}/registry') + include ('*.setreg') + }} + + compile{config}Sources.dependsOn copyRegistryFolder{config} +""" + +CUSTOM_GRADLE_COPY_REGISTRY_FOLDER_DEPENDENCY_FORMAT_STR = """ + + copyRegistryFolder{config}.mustRunAfter {{ + tasks.findAll {{ task->task.name.contains('syncLYLayoutMode{config}') }} + }} +""" + CUSTOM_APPLY_ASSET_LAYOUT_TASK_FORMAT_STR = """ task syncLYLayoutMode{config}(type:Exec) {{ workingDir '{working_dir}' @@ -851,14 +868,13 @@ class AndroidProjectGenerator(object): config=native_config) # Copy over settings registry files from the Registry folder with build output directory gradle_build_env[f'CUSTOM_APPLY_ASSET_LAYOUT_{native_config_upper}_TASK'] += \ - CUSTOM_GRADLE_COPY_NATIVE_CONFIG_BUILD_ARTIFACTS_FORMAT_STR.format(config=native_config, - config_lower=native_config_lower, - asset_layout_folder=(self.build_dir / 'app/src/main/assets').resolve().as_posix(), - file_includes='**/Registry/*.setreg') + CUSTOM_GRADLE_COPY_REGISTRY_FOLDER_FORMAT_STR.format(config=native_config, + config_lower=native_config_lower, + asset_layout_folder=(self.build_dir / 'app/src/main/assets').resolve().as_posix()) if self.include_assets_in_apk: # This is a dependency of the layout sync only if we are including assets in the APK gradle_build_env[f'CUSTOM_APPLY_ASSET_LAYOUT_{native_config_upper}_TASK'] += \ - CUSTOM_GRADLE_COPY_NATIVE_CONFIG_BUILD_ARTIFACTS_DEPENDENCY_FORMAT_STR.format(config=native_config) + CUSTOM_GRADLE_COPY_REGISTRY_FOLDER_DEPENDENCY_FORMAT_STR.format(config=native_config) From 23322edde7e138e4466e5f9de739b682c0621a65 Mon Sep 17 00:00:00 2001 From: chiyenteng <82238204+chiyenteng@users.noreply.github.com> Date: Fri, 1 Oct 2021 10:02:00 -0700 Subject: [PATCH 46/50] Fix Entity id consistency issue & refactor prefab workflows/tests (#4373) * Fix Entity id consistency issue & refactor prefab workflows/test framework Signed-off-by: chiyteng * Update comments Signed-off-by: chiyteng * Modify CreatePrefab and remove extra spaces Signed-off-by: chiyteng * Address comments Signed-off-by: chiyteng * Refactor prefab instance constructors Signed-off-by: chiyteng * Remove commented out code Signed-off-by: chiyteng --- .../Gem/PythonTests/prefab/Prefab.py | 117 +++++++++--------- ...fab_BasicWorkflow_CreateAndDeletePrefab.py | 3 +- ...b_BasicWorkflow_CreateAndReparentPrefab.py | 6 +- .../Prefab_BasicWorkflow_InstantiatePrefab.py | 4 +- .../PythonTests/prefab/Prefab_Test_Utils.py | 16 +-- .../PrefabEditorEntityOwnershipService.cpp | 38 +++--- .../Prefab/Instance/Instance.cpp | 64 +++++++--- .../Prefab/Instance/Instance.h | 10 +- .../Instance/TemplateInstanceMapper.cpp | 8 +- .../Prefab/Instance/TemplateInstanceMapper.h | 6 +- .../TemplateInstanceMapperInterface.h | 2 +- .../AzToolsFramework/Prefab/Link/Link.cpp | 4 +- .../AzToolsFramework/Prefab/Link/Link.h | 4 +- .../Prefab/PrefabSystemComponent.cpp | 50 ++++---- .../Prefab/PrefabSystemComponent.h | 62 ++++++---- .../Prefab/PrefabSystemComponentInterface.h | 21 ++-- .../AzToolsFramework/Prefab/PrefabUndo.cpp | 6 +- .../AzToolsFramework/Prefab/PrefabUndo.h | 6 +- .../Benchmark/PrefabCreateBenchmarks.cpp | 4 +- .../PrefabUpdateInstancesBenchmarks.cpp | 8 +- .../Prefab/PrefabFocus/PrefabFocusTests.cpp | 2 +- ...refabInstanceToTemplatePropagatorTests.cpp | 2 +- .../Tests/Prefab/PrefabInstantiateTests.cpp | 4 +- .../Tests/Prefab/PrefabTestDataUtils.cpp | 4 +- .../Tests/Prefab/PrefabTestDataUtils.h | 4 +- .../Tests/Prefab/PrefabTestDomUtils.cpp | 6 +- .../Tests/Prefab/PrefabTestDomUtils.h | 6 +- .../Tests/Prefab/PrefabTestUndoFixture.cpp | 4 +- .../Prefab/PrefabUpdateInstancesTests.cpp | 4 +- .../Prefab/PrefabUpdateTemplateTests.cpp | 28 ++--- .../Prefab/PrefabUpdateWithPatchesTests.cpp | 2 +- .../SerializeContextTools/SliceConverter.cpp | 4 +- 32 files changed, 284 insertions(+), 225 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab.py index 14a1ab62f0..9b4d2d1393 100644 --- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab.py +++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab.py @@ -25,28 +25,39 @@ import prefab.Prefab_Test_Utils as prefab_test_utils # This is a helper class which contains some of the useful information about a prefab instance. class PrefabInstance: - def __init__(self, name: str=None, prefab_file_name: str=None, container_entity: EditorEntity=EntityId()): - self.name = name + def __init__(self, prefab_file_name: str=None, container_entity: EditorEntity=EntityId()): self.prefab_file_name: str = prefab_file_name self.container_entity: EditorEntity = container_entity + def __eq__(self, other): + return other and self.container_entity.id == other.container_entity.id + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash(self.container_entity.id) + """ See if this instance is valid to be used with other prefab operations. :return: Whether the target instance is valid or not. """ def is_valid() -> bool: - return self.container_entity.id.IsValid() and self.name is not None and self.prefab_file_name in Prefab.existing_prefabs + return self.container_entity.id.IsValid() and self.prefab_file_name in Prefab.existing_prefabs - """ Reparent this instance to target parent entity. The function will also check pop up dialog ui in editor to see if there's prefab cyclical dependency error while reparenting prefabs. :param parent_entity_id: The id of the entity this instance should be a child of in the transform hierarchy next. """ async def ui_reparent_prefab_instance(self, parent_entity_id: EntityId): - container_entity_name = self.container_entity.get_name() - current_children_entity_ids_having_prefab_name = prefab_test_utils.get_children_ids_by_name(parent_entity_id, container_entity_name) - Report.info(f'current_children_entity_ids_having_prefab_name: {current_children_entity_ids_having_prefab_name}') + container_entity_id_before_reparent = self.container_entity.id + + original_parent = EditorEntity(self.container_entity.get_parent_id()) + original_parent_before_reparent_children_ids = set(original_parent.get_children_ids()) + + new_parent = EditorEntity(parent_entity_id) + new_parent_before_reparent_children_ids = set(new_parent.get_children_ids()) pyside_utils.run_soon(lambda: self.container_entity.set_parent_entity(parent_entity_id)) pyside_utils.run_soon(lambda: prefab_test_utils.wait_for_propagation()) @@ -60,18 +71,23 @@ class PrefabInstance: except pyside_utils.EventLoopTimeoutException: pass - updated_children_entity_ids_having_prefab_name = prefab_test_utils.get_children_ids_by_name(parent_entity_id, container_entity_name) - Report.info(f'updated_children_entity_ids_having_prefab_name: {updated_children_entity_ids_having_prefab_name}') - new_child_with_reparented_prefab_name_added = len(updated_children_entity_ids_having_prefab_name) == len(current_children_entity_ids_having_prefab_name) + 1 - assert new_child_with_reparented_prefab_name_added, "No entity with reparented prefab name become a child of target parent entity" + original_parent_after_reparent_children_ids = set(original_parent.get_children_ids()) + assert len(original_parent_after_reparent_children_ids) == len(original_parent_before_reparent_children_ids) - 1, \ + "The children count of the Prefab Instance's original parent should be decreased by 1." + assert not container_entity_id_before_reparent in original_parent_after_reparent_children_ids, \ + "This Prefab Instance is still a child entity of its original parent entity." + + new_parent_after_reparent_children_ids = set(new_parent.get_children_ids()) + assert len(new_parent_after_reparent_children_ids) == len(new_parent_before_reparent_children_ids) + 1, \ + "The children count of the Prefab Instance's new parent should be increased by 1." - updated_container_entity_id = set(updated_children_entity_ids_having_prefab_name).difference(current_children_entity_ids_having_prefab_name).pop() - updated_container_entity = EditorEntity(updated_container_entity_id) - updated_container_entity_parent_id = updated_container_entity.get_parent_id() - has_correct_parent = updated_container_entity_parent_id.ToString() == parent_entity_id.ToString() - assert has_correct_parent, "Prefab reparented is *not* under the expected parent entity" + container_entity_id_after_reparent = set(new_parent_after_reparent_children_ids).difference(new_parent_before_reparent_children_ids).pop() + reparented_container_entity = EditorEntity(container_entity_id_after_reparent) + reparented_container_entity_parent_id = reparented_container_entity.get_parent_id() + has_correct_parent = reparented_container_entity_parent_id.ToString() == parent_entity_id.ToString() + assert has_correct_parent, "Prefab Instance reparented is *not* under the expected parent entity" - self.container_entity = EditorEntity(updated_container_entity_id) + self.container_entity = reparented_container_entity # This is a helper class which contains some of the useful information about a prefab template. class Prefab: @@ -81,7 +97,7 @@ class Prefab: def __init__(self, file_name: str): self.file_name:str = file_name self.file_path: str = prefab_test_utils.get_prefab_file_path(file_name) - self.instances: dict = {} + self.instances: set[PrefabInstance] = set() """ Check if a prefab is ready to be used to generate its instances. @@ -122,10 +138,10 @@ class Prefab: :param entities: The entities that should form the new prefab (along with their descendants). :param file_name: A unique file name of new prefab. :param prefab_instance_name: A name for the very first instance generated while prefab creation. The default instance name is the same as file_name. - :return: An outcome object with an entityId of the new prefab's container entity; on failure, it comes with an error message detailing the cause of the error. + :return: Created Prefab object and the very first PrefabInstance object owned by the prefab. """ @classmethod - def create_prefab(cls, entities: list[EditorEntity], file_name: str, prefab_instance_name: str=None) -> Prefab: + def create_prefab(cls, entities: list[EditorEntity], file_name: str, prefab_instance_name: str=None) -> (Prefab, PrefabInstance): assert not Prefab.is_prefab_loaded(file_name), f"Can't create Prefab '{file_name}' since the prefab already exists" new_prefab = Prefab(file_name) @@ -133,18 +149,18 @@ class Prefab: create_prefab_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'CreatePrefabInMemory', entity_ids, new_prefab.file_path) assert create_prefab_result.IsSuccess(), f"Prefab operation 'CreatePrefab' failed. Error: {create_prefab_result.GetError()}" - container_entity = EditorEntity(create_prefab_result.GetValue()) + container_entity_id = create_prefab_result.GetValue() + container_entity = EditorEntity(container_entity_id) if prefab_instance_name: container_entity.set_name(prefab_instance_name) - else: - prefab_instance_name = file_name prefab_test_utils.wait_for_propagation() - container_entity_id = prefab_test_utils.find_entity_by_unique_name(prefab_instance_name) - new_prefab.instances[prefab_instance_name] = PrefabInstance(prefab_instance_name, file_name, EditorEntity(container_entity_id)) + + new_prefab_instance = PrefabInstance(file_name, EditorEntity(container_entity_id)) + new_prefab.instances.add(new_prefab_instance) Prefab.existing_prefabs[file_name] = new_prefab - return new_prefab + return new_prefab, new_prefab_instance """ Remove target prefab instances. @@ -152,22 +168,15 @@ class Prefab: """ @classmethod def remove_prefabs(cls, prefab_instances: list[PrefabInstance]): - instances_to_remove_name_counts = Counter() - instances_removed_expected_name_counts = Counter() - - entities_to_remove = [prefab_instance.container_entity for prefab_instance in prefab_instances] - while entities_to_remove: - entity = entities_to_remove.pop(-1) - entity_name = entity.get_name() - instances_to_remove_name_counts[entity_name] += 1 - + entity_ids_to_remove = [] + entity_id_queue = [prefab_instance.container_entity for prefab_instance in prefab_instances] + while entity_id_queue: + entity = entity_id_queue.pop(0) children_entity_ids = entity.get_children_ids() for child_entity_id in children_entity_ids: - entities_to_remove.append(EditorEntity(child_entity_id)) + entity_id_queue.append(EditorEntity(child_entity_id)) - for entity_name, entity_count in instances_to_remove_name_counts.items(): - entities = prefab_test_utils.find_entities_by_name(entity_name) - instances_removed_expected_name_counts[entity_name] = len(entities) - entity_count + entity_ids_to_remove.append(entity.id) container_entity_ids = [prefab_instance.container_entity.id for prefab_instance in prefab_instances] delete_prefab_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'DeleteEntitiesAndAllDescendantsInInstance', container_entity_ids) @@ -175,28 +184,24 @@ class Prefab: prefab_test_utils.wait_for_propagation() - prefab_entities_deleted = True - for entity_name, expected_entity_count in instances_removed_expected_name_counts.items(): - actual_entity_count = len(prefab_test_utils.find_entities_by_name(entity_name)) - if actual_entity_count is not expected_entity_count: - prefab_entities_deleted = False - break - - assert prefab_entities_deleted, "Not all entities and descendants in target prefabs are deleted." + entity_ids_after_delete = set(prefab_test_utils.get_all_entities()) + for entity_id_removed in entity_ids_to_remove: + if entity_id_removed in entity_ids_after_delete: + assert prefab_entities_deleted, "Not all entities and descendants in target prefabs are deleted." for instance in prefab_instances: instance_deleted_prefab = Prefab.get_prefab(instance.prefab_file_name) - instance_deleted_prefab.instances.pop(instance.name) + instance_deleted_prefab.instances.remove(instance) instance = PrefabInstance() """ Instantiate an instance of this prefab. - :param name: A name for newly instantiated prefab instance. The default instance name is the same as this prefab's file name. :param parent_entity: The entity the prefab should be a child of in the transform hierarchy. + :param name: A name for newly instantiated prefab instance. The default instance name is the same as this prefab's file name. :param prefab_position: The position in world space the prefab should be instantiated in. - :return: An outcome object with an entityId of the new prefab's container entity; on failure, it comes with an error message detailing the cause of the error. + :return: Instantiated PrefabInstance object owned by this prefab. """ - def instantiate(self, name: str=None, parent_entity: EditorEntity=None, prefab_position: Vector3=Vector3()) -> PrefabInstance: + def instantiate(self, parent_entity: EditorEntity=None, name: str=None, prefab_position: Vector3=Vector3()) -> PrefabInstance: parent_entity_id = parent_entity.id if parent_entity is not None else EntityId() instantiate_prefab_result = prefab.PrefabPublicRequestBus( @@ -209,13 +214,13 @@ class Prefab: if name: container_entity.set_name(name) - else: - name = self.file_name prefab_test_utils.wait_for_propagation() - container_entity_id = prefab_test_utils.find_entity_by_unique_name(name) - self.instances[name] = PrefabInstance(name, self.file_name, EditorEntity(container_entity_id)) + + new_prefab_instance = PrefabInstance(self.file_name, EditorEntity(container_entity_id)) + assert not new_prefab_instance in self.instances, "This prefab instance is already existed before this instantiation." + self.instances.add(new_prefab_instance) prefab_test_utils.check_entity_at_position(container_entity_id, prefab_position) - return container_entity_id + return new_prefab_instance diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndDeletePrefab.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndDeletePrefab.py index c6e0daa4dd..f3fbcfa6ad 100644 --- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndDeletePrefab.py +++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndDeletePrefab.py @@ -22,11 +22,10 @@ def Prefab_BasicWorkflow_CreateAndDeletePrefab(): car_prefab_entities = [car_entity] # Checks for prefab creation passed or not - car_prefab = Prefab.create_prefab( + _, car = Prefab.create_prefab( car_prefab_entities, CAR_PREFAB_FILE_NAME) # Checks for prefab deletion passed or not - car = car_prefab.instances[CAR_PREFAB_FILE_NAME] Prefab.remove_prefabs([car]) if __name__ == "__main__": diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndReparentPrefab.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndReparentPrefab.py index 04f7b97628..e5a9d9930a 100644 --- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndReparentPrefab.py +++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndReparentPrefab.py @@ -28,7 +28,7 @@ def Prefab_BasicWorkflow_CreateAndReparentPrefab(): car_prefab_entities = [car_entity] # Checks for prefab creation passed or not - car_prefab = Prefab.create_prefab( + _, car = Prefab.create_prefab( car_prefab_entities, CAR_PREFAB_FILE_NAME) # Creates another new Entity at the root level @@ -36,12 +36,10 @@ def Prefab_BasicWorkflow_CreateAndReparentPrefab(): wheel_prefab_entities = [wheel_entity] # Checks for wheel prefab creation passed or not - wheel_prefab = Prefab.create_prefab( + _, wheel = Prefab.create_prefab( wheel_prefab_entities, WHEEL_PREFAB_FILE_NAME) # Checks for prefab reparenting passed or not - car = car_prefab.instances[CAR_PREFAB_FILE_NAME] - wheel = wheel_prefab.instances[WHEEL_PREFAB_FILE_NAME] await wheel.ui_reparent_prefab_instance(car.container_entity.id) run_test() diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_InstantiatePrefab.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_InstantiatePrefab.py index b9015ab556..46be669697 100644 --- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_InstantiatePrefab.py +++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_InstantiatePrefab.py @@ -22,11 +22,11 @@ def Prefab_BasicWorkflow_InstantiatePrefab(): # Checks for prefab instantiation passed or not test_prefab = Prefab.get_prefab(EXISTING_TEST_PREFAB_FILE_NAME) - instantiated_test_container_entity_id = test_prefab.instantiate( + test_instance = test_prefab.instantiate( prefab_position=INSTANTIATED_TEST_PREFAB_POSITION) prefab_test_utils.check_entity_children_count( - instantiated_test_container_entity_id, + test_instance.container_entity.id, EXPECTED_TEST_PREFAB_CHILDREN_COUNT) if __name__ == "__main__": diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_Test_Utils.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_Test_Utils.py index 8cd59ed077..3e19911449 100644 --- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_Test_Utils.py +++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_Test_Utils.py @@ -29,20 +29,8 @@ def find_entities_by_name(entity_name): searchFilter.names = [entity_name] return entity.SearchBus(bus.Broadcast, 'SearchEntities', searchFilter) -def find_entity_by_unique_name(entity_name): - unique_name_entity_found_result = ( - "Entity with a unique name found", - "Entity with a unique name *not* found") - - entities = find_entities_by_name(entity_name) - unique_name_entity_found = len(entities) == 1 - Report.result(unique_name_entity_found_result, unique_name_entity_found) - - if unique_name_entity_found: - return entities[0] - else: - Report.info(f"{len(entities)} entities with name '{entity_name}' found") - return EntityId() +def get_all_entities(): + return entity.SearchBus(bus.Broadcast, 'SearchEntities', entity.SearchFilter()) def check_entity_at_position(entity_id, expected_entity_position): entity_at_expected_position_result = ( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp index e5daf2674d..7db507e751 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp @@ -18,8 +18,9 @@ #include #include #include -#include #include +#include +#include #include #include #include @@ -317,17 +318,18 @@ namespace AzToolsFramework const AZStd::vector& entities, AZStd::vector>&& nestedPrefabInstances, AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder) { - AZStd::unique_ptr createdPrefabInstance = - m_prefabSystemComponent->CreatePrefab(entities, AZStd::move(nestedPrefabInstances), filePath, nullptr, false); + if (!instanceToParentUnder) + { + instanceToParentUnder = *m_rootInstance; + } + + AZStd::unique_ptr createdPrefabInstance = m_prefabSystemComponent->CreatePrefab( + entities, AZStd::move(nestedPrefabInstances), filePath, nullptr, instanceToParentUnder, false); if (createdPrefabInstance) { - if (!instanceToParentUnder) - { - instanceToParentUnder = *m_rootInstance; - } - - Prefab::Instance& addedInstance = instanceToParentUnder->get().AddInstance(AZStd::move(createdPrefabInstance)); + Prefab::Instance& addedInstance = instanceToParentUnder->get().AddInstance( + AZStd::move(createdPrefabInstance)); AZ::Entity* containerEntity = addedInstance.m_containerEntity.get(); containerEntity->AddComponent(aznew Prefab::EditorPrefabComponent()); HandleEntitiesAdded({containerEntity}); @@ -341,16 +343,18 @@ namespace AzToolsFramework Prefab::InstanceOptionalReference PrefabEditorEntityOwnershipService::InstantiatePrefab( AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder) { - AZStd::unique_ptr createdPrefabInstance = m_prefabSystemComponent->InstantiatePrefab(filePath); - - if (createdPrefabInstance) + if (!instanceToParentUnder) { - if (!instanceToParentUnder) - { - instanceToParentUnder = *m_rootInstance; - } + instanceToParentUnder = *m_rootInstance; + } - Prefab::Instance& addedInstance = instanceToParentUnder->get().AddInstance(AZStd::move(createdPrefabInstance)); + AZStd::unique_ptr instantiatedPrefabInstance = + m_prefabSystemComponent->InstantiatePrefab(filePath, instanceToParentUnder); + + if (instantiatedPrefabInstance) + { + Prefab::Instance& addedInstance = instanceToParentUnder->get().AddInstance( + AZStd::move(instantiatedPrefabInstance)); HandleEntitiesAdded({addedInstance.m_containerEntity.get()}); return addedInstance; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp index 54e7f7608c..b5db46d0db 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -28,24 +29,52 @@ namespace AzToolsFramework } Instance::Instance(AZStd::unique_ptr containerEntity) + : Instance(AZStd::move(containerEntity), AZStd::nullopt, GenerateInstanceAlias()) { - m_instanceEntityMapper = AZ::Interface::Get(); + } + Instance::Instance(InstanceOptionalReference parent) + : Instance(nullptr, parent, GenerateInstanceAlias()) + { + } + + Instance::Instance(InstanceAlias alias) + : Instance(nullptr, AZStd::nullopt, AZStd::move(alias)) + { + } + + Instance::Instance(AZStd::unique_ptr containerEntity, InstanceOptionalReference parent) + : Instance(AZStd::move(containerEntity), parent, GenerateInstanceAlias()) + { + } + + Instance::Instance(AZStd::unique_ptr containerEntity, InstanceOptionalReference parent, InstanceAlias alias) + : m_parent(parent.has_value() ? &parent->get() : nullptr) + , m_alias(AZStd::move(alias)) + , m_containerEntity(containerEntity ? AZStd::move(containerEntity) : AZStd::make_unique()) + , m_instanceEntityMapper(AZ::Interface::Get()) + , m_templateInstanceMapper(AZ::Interface::Get()) + { AZ_Assert(m_instanceEntityMapper, "Instance Entity Mapper Interface could not be found. " "It is a requirement for the Prefab Instance class. " "Check that it is being correctly initialized."); - m_templateInstanceMapper = AZ::Interface::Get(); - AZ_Assert(m_templateInstanceMapper, "Template Instance Mapper Interface could not be found. " "It is a requirement for the Prefab Instance class. " "Check that it is being correctly initialized."); - m_alias = GenerateInstanceAlias(); - m_containerEntity = containerEntity ? AZStd::move(containerEntity) - : AZStd::make_unique(); + if (parent) + { + AliasPath absoluteInstancePath = m_parent->GetAbsoluteInstanceAliasPath(); + absoluteInstancePath.Append(m_alias); + absoluteInstancePath.Append(PrefabDomUtils::ContainerEntityName); + + AZ::EntityId newContainerEntityId = InstanceEntityIdMapper::GenerateEntityIdForAliasPath(absoluteInstancePath); + m_containerEntity->SetId(newContainerEntityId); + } + RegisterEntity(m_containerEntity->GetId(), PrefabDomUtils::ContainerEntityName); } @@ -69,12 +98,12 @@ namespace AzToolsFramework } } - const TemplateId& Instance::GetTemplateId() const + TemplateId Instance::GetTemplateId() const { return m_templateId; } - void Instance::SetTemplateId(const TemplateId& templateId) + void Instance::SetTemplateId(TemplateId templateId) { // If we aren't changing the template Id, there's no need to unregister / re-register if (templateId == m_templateId) @@ -295,20 +324,21 @@ namespace AzToolsFramework } Instance& Instance::AddInstance(AZStd::unique_ptr instance) - { - InstanceAlias newInstanceAlias = GenerateInstanceAlias(); - return AddInstance(AZStd::move(instance), newInstanceAlias); - } - - Instance& Instance::AddInstance(AZStd::unique_ptr instance, InstanceAlias newInstanceAlias) { AZ_Assert(instance.get(), "instance argument is nullptr"); + + if (instance->GetInstanceAlias().empty()) + { + instance->m_alias = GenerateInstanceAlias(); + } + AZ_Assert( - m_nestedInstances.find(newInstanceAlias) == m_nestedInstances.end(), + m_nestedInstances.find(instance->GetInstanceAlias()) == m_nestedInstances.end(), "InstanceAlias' unique id collision, this should never happen."); + instance->m_parent = this; - instance->m_alias = newInstanceAlias; - return *(m_nestedInstances[newInstanceAlias] = std::move(instance)); + auto& alias = instance->GetInstanceAlias(); + return *(m_nestedInstances[alias] = AZStd::move(instance)); } void Instance::DetachNestedInstances(const AZStd::function)>& callback) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h index 39d364b4bb..50a39268fe 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h @@ -65,6 +65,9 @@ namespace AzToolsFramework Instance(); explicit Instance(AZStd::unique_ptr containerEntity); + explicit Instance(InstanceOptionalReference parent); + explicit Instance(AZStd::unique_ptr containerEntity, InstanceOptionalReference parent); + explicit Instance(InstanceAlias alias); virtual ~Instance(); Instance(const Instance& rhs) = delete; @@ -72,8 +75,8 @@ namespace AzToolsFramework static void Reflect(AZ::ReflectContext* context); - const TemplateId& GetTemplateId() const; - void SetTemplateId(const TemplateId& templateId); + TemplateId GetTemplateId() const; + void SetTemplateId(TemplateId templateId); const AZ::IO::Path& GetTemplateSourcePath() const; void SetTemplateSourcePath(AZ::IO::PathView sourcePath); @@ -97,7 +100,6 @@ namespace AzToolsFramework void Reset(); Instance& AddInstance(AZStd::unique_ptr instance); - Instance& AddInstance(AZStd::unique_ptr instance, InstanceAlias instanceAlias); AZStd::unique_ptr DetachNestedInstance(const InstanceAlias& instanceAlias); void DetachNestedInstances(const AZStd::function)>& callback); @@ -184,6 +186,8 @@ namespace AzToolsFramework private: static constexpr const char s_aliasPathSeparator = '/'; + Instance(AZStd::unique_ptr containerEntity, InstanceOptionalReference parent, InstanceAlias alias); + void ClearEntities(); void RemoveEntities(const AZStd::function&)>& filter); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.cpp index 65c498499d..5c7e5070f0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.cpp @@ -27,7 +27,7 @@ namespace AzToolsFramework } - bool TemplateInstanceMapper::RegisterTemplate(const TemplateId& templateId) + bool TemplateInstanceMapper::RegisterTemplate(TemplateId templateId) { const bool result = m_templateIdToInstancesMap.emplace(templateId, InstanceSet()).second; AZ_Assert(result, @@ -39,7 +39,7 @@ namespace AzToolsFramework return result; } - bool TemplateInstanceMapper::UnregisterTemplate(const TemplateId& templateId) + bool TemplateInstanceMapper::UnregisterTemplate(TemplateId templateId) { const bool result = m_templateIdToInstancesMap.erase(templateId) != 0; AZ_Assert(result, @@ -53,7 +53,7 @@ namespace AzToolsFramework bool TemplateInstanceMapper::RegisterInstanceToTemplate(Instance& instance) { - const TemplateId& templateId = instance.GetTemplateId(); + TemplateId templateId = instance.GetTemplateId(); if (templateId == InvalidTemplateId) { return false; @@ -79,7 +79,7 @@ namespace AzToolsFramework found->second.erase(&instance) != 0; } - InstanceSetConstReference TemplateInstanceMapper::FindInstancesOwnedByTemplate(const TemplateId& templateId) const + InstanceSetConstReference TemplateInstanceMapper::FindInstancesOwnedByTemplate(TemplateId templateId) const { auto found = m_templateIdToInstancesMap.find(templateId); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.h index 307996b381..a2330c30d2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.h @@ -26,10 +26,10 @@ namespace AzToolsFramework TemplateInstanceMapper(); ~TemplateInstanceMapper() override; - InstanceSetConstReference FindInstancesOwnedByTemplate(const TemplateId& templateId) const override; + InstanceSetConstReference FindInstancesOwnedByTemplate(TemplateId templateId) const override; - bool RegisterTemplate(const TemplateId& templateId); - bool UnregisterTemplate(const TemplateId& templateId); + bool RegisterTemplate(TemplateId templateId); + bool UnregisterTemplate(TemplateId templateId); protected: bool RegisterInstanceToTemplate(Instance& instance) override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapperInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapperInterface.h index 6473d5e937..475b456425 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapperInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapperInterface.h @@ -24,7 +24,7 @@ namespace AzToolsFramework AZ_RTTI(TemplateInstanceMapperInterface, "{5DCCCDAA-3441-4266-9670-B349386E0129}"); virtual ~TemplateInstanceMapperInterface() = default; - virtual InstanceSetConstReference FindInstancesOwnedByTemplate(const TemplateId& templateId) const = 0; + virtual InstanceSetConstReference FindInstancesOwnedByTemplate(TemplateId templateId) const = 0; protected: // Only the Instance class is allowed to register and unregister Instances. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Link/Link.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Link/Link.cpp index 800a90c622..8efb62d7e8 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Link/Link.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Link/Link.cpp @@ -122,12 +122,12 @@ namespace AzToolsFramework !m_instanceName.empty(); } - const TemplateId& Link::GetSourceTemplateId() const + TemplateId Link::GetSourceTemplateId() const { return m_sourceTemplateId; } - const TemplateId& Link::GetTargetTemplateId() const + TemplateId Link::GetTargetTemplateId() const { return m_targetTemplateId; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Link/Link.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Link/Link.h index 00530c4337..aa11262bdf 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Link/Link.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Link/Link.h @@ -48,8 +48,8 @@ namespace AzToolsFramework bool IsValid() const; - const TemplateId& GetSourceTemplateId() const; - const TemplateId& GetTargetTemplateId() const; + TemplateId GetSourceTemplateId() const; + TemplateId GetTargetTemplateId() const; LinkId GetId() const; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp index 6ef2d756fb..29bad78b1c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp @@ -92,7 +92,17 @@ namespace AzToolsFramework AZStd::unique_ptr PrefabSystemComponent::CreatePrefab( const AZStd::vector& entities, AZStd::vector>&& instancesToConsume, - AZ::IO::PathView filePath, AZStd::unique_ptr containerEntity, bool shouldCreateLinks) + AZ::IO::PathView filePath, AZStd::unique_ptr containerEntity, InstanceOptionalReference parent, + bool shouldCreateLinks) + { + AZStd::unique_ptr newInstance = AZStd::make_unique(AZStd::move(containerEntity), parent); + CreatePrefab(entities, AZStd::move(instancesToConsume), filePath, newInstance, shouldCreateLinks); + return newInstance; + } + + void PrefabSystemComponent::CreatePrefab( + const AZStd::vector& entities, AZStd::vector>&& instancesToConsume, + AZ::IO::PathView filePath, AZStd::unique_ptr& newInstance, bool shouldCreateLinks) { AZ::IO::Path relativeFilePath = m_prefabLoader.GenerateRelativePath(filePath); if (GetTemplateIdFromFilePath(relativeFilePath) != InvalidTemplateId) @@ -101,11 +111,9 @@ namespace AzToolsFramework "Filepath %s has already been registered with the Prefab System Component", relativeFilePath.c_str()); - return nullptr; + return; } - AZStd::unique_ptr newInstance = AZStd::make_unique(AZStd::move(containerEntity)); - for (AZ::Entity* entity : entities) { AZ_Assert(entity, "Prefab - Null entity passed in during Create Prefab"); @@ -136,8 +144,6 @@ namespace AzToolsFramework { newInstance->SetTemplateId(newTemplateId); } - - return newInstance; } void PrefabSystemComponent::PropagateTemplateChanges(TemplateId templateId, InstanceOptionalReference instanceToExclude) @@ -171,7 +177,7 @@ namespace AzToolsFramework } } - void PrefabSystemComponent::UpdatePrefabInstances(const TemplateId& templateId, InstanceOptionalReference instanceToExclude) + void PrefabSystemComponent::UpdatePrefabInstances(TemplateId templateId, InstanceOptionalReference instanceToExclude) { m_instanceUpdateExecutor.AddTemplateInstancesToQueue(templateId, instanceToExclude); } @@ -256,7 +262,8 @@ namespace AzToolsFramework } } - AZStd::unique_ptr PrefabSystemComponent::InstantiatePrefab(AZ::IO::PathView filePath) + AZStd::unique_ptr PrefabSystemComponent::InstantiatePrefab( + AZ::IO::PathView filePath, InstanceOptionalReference parent) { // Retrieve the template id for the source prefab filepath Prefab::TemplateId templateId = GetTemplateIdFromFilePath(filePath); @@ -276,10 +283,11 @@ namespace AzToolsFramework return nullptr; } - return InstantiatePrefab(templateId); + return InstantiatePrefab(templateId, parent); } - AZStd::unique_ptr PrefabSystemComponent::InstantiatePrefab(const TemplateId& templateId) + AZStd::unique_ptr PrefabSystemComponent::InstantiatePrefab( + TemplateId templateId, InstanceOptionalReference parent) { TemplateReference instantiatingTemplate = FindTemplate(templateId); @@ -292,7 +300,7 @@ namespace AzToolsFramework return nullptr; } - auto newInstance = AZStd::make_unique(); + auto newInstance = AZStd::make_unique(parent); Instance::EntityList newEntities; if (!PrefabDomUtils::LoadInstanceFromPrefabDom(*newInstance, newEntities, instantiatingTemplate->get().GetPrefabDom())) { @@ -354,7 +362,7 @@ namespace AzToolsFramework return newTemplateId; } - TemplateReference PrefabSystemComponent::FindTemplate(const TemplateId& id) + TemplateReference PrefabSystemComponent::FindTemplate(TemplateId id) { auto found = m_templateIdMap.find(id); if (found != m_templateIdMap.end()) @@ -466,7 +474,7 @@ namespace AzToolsFramework templateToChange.SetFilePath(filePath); } - void PrefabSystemComponent::RemoveTemplate(const TemplateId& templateId) + void PrefabSystemComponent::RemoveTemplate(TemplateId templateId) { auto findTemplateResult = FindTemplate(templateId); if (!findTemplateResult.has_value()) @@ -553,8 +561,8 @@ namespace AzToolsFramework } LinkId PrefabSystemComponent::AddLink( - const TemplateId& sourceTemplateId, - const TemplateId& targetTemplateId, + TemplateId sourceTemplateId, + TemplateId targetTemplateId, PrefabDomValue::MemberIterator& instanceIterator, InstanceOptionalReference instance) { @@ -616,8 +624,8 @@ namespace AzToolsFramework } LinkId PrefabSystemComponent::CreateLink( - const TemplateId& linkTargetId, - const TemplateId& linkSourceId, + TemplateId linkTargetId, + TemplateId linkSourceId, const InstanceAlias& instanceAlias, const PrefabDomConstReference linkPatches, const LinkId& linkId) @@ -774,7 +782,7 @@ namespace AzToolsFramework } } - bool PrefabSystemComponent::IsTemplateDirty(const TemplateId& templateId) + bool PrefabSystemComponent::IsTemplateDirty(TemplateId templateId) { auto templateRef = FindTemplate(templateId); @@ -786,7 +794,7 @@ namespace AzToolsFramework return false; } - void PrefabSystemComponent::SetTemplateDirtyFlag(const TemplateId& templateId, bool dirty) + void PrefabSystemComponent::SetTemplateDirtyFlag(TemplateId templateId, bool dirty) { auto templateRef = FindTemplate(templateId); @@ -940,7 +948,7 @@ namespace AzToolsFramework return true; } - bool PrefabSystemComponent::GenerateLinksForNewTemplate(const TemplateId& newTemplateId, Instance& instance) + bool PrefabSystemComponent::GenerateLinksForNewTemplate(TemplateId newTemplateId, Instance& instance) { TemplateReference newTemplateReference = FindTemplate(newTemplateId); if (!newTemplateReference.has_value()) @@ -980,7 +988,7 @@ namespace AzToolsFramework } const PrefabDomValue& source = instanceSourceReference->get(); - const TemplateId& nestedTemplateId = GetTemplateIdFromFilePath(source.GetString()); + TemplateId nestedTemplateId = GetTemplateIdFromFilePath(source.GetString()); if (nestedTemplateId == InvalidTemplateId) { AZ_Error("Prefab", false, diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h index 746c306c2b..19c7aeb8a9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h @@ -84,7 +84,7 @@ namespace AzToolsFramework * @param id A unique id of a Template. * @return Reference of Template if the Template exists. */ - TemplateReference FindTemplate(const TemplateId& id) override; + TemplateReference FindTemplate(TemplateId id) override; /** * Find Link with given Link id from Prefab System Component. @@ -112,7 +112,7 @@ namespace AzToolsFramework * Remove the Template associated with the given id from Prefab System Component. * @param templateId A unique id of a Template. */ - void RemoveTemplate(const TemplateId& templateId) override; + void RemoveTemplate(TemplateId templateId) override; /** * Remove all Templates from the Prefab System Component. @@ -121,17 +121,21 @@ namespace AzToolsFramework /** * Generates a new Prefab Instance based on the Template whose source is stored in filepath. - * @param filePath the path to the prefab source file containing the template being instantiated. + * @param filePath The path to the prefab source file containing the template being instantiated. + * @param parent Reference of the target instance the instantiated instance will be placed under. * @return A unique_ptr to the newly instantiated instance. Null if operation failed. */ - AZStd::unique_ptr InstantiatePrefab(AZ::IO::PathView filePath) override; + AZStd::unique_ptr InstantiatePrefab( + AZ::IO::PathView filePath, InstanceOptionalReference parent = AZStd::nullopt) override; /** - * Generates a new Prefab Instance based on the Template referenced by templateId - * @param templateId the id of the template being instantiated. + * Generates a new Prefab Instance based on the Template referenced by templateId. + * @param templateId The id of the template being instantiated. + * @param parent Reference of the target instance the instantiated instance will be placed under. * @return A unique_ptr to the newly instantiated instance. Null if operation failed. */ - AZStd::unique_ptr InstantiatePrefab(const TemplateId& templateId) override; + AZStd::unique_ptr InstantiatePrefab( + TemplateId templateId, InstanceOptionalReference parent = AZStd::nullopt) override; /** * Add a new Link into Prefab System Component and create a unique id for it. @@ -142,8 +146,8 @@ namespace AzToolsFramework * @return A unique id for the new Link. */ LinkId AddLink( - const TemplateId& sourceTemplateId, - const TemplateId& targetTemplateId, + TemplateId sourceTemplateId, + TemplateId targetTemplateId, PrefabDomValue::MemberIterator& instanceIterator, InstanceOptionalReference instance) override; @@ -157,8 +161,8 @@ namespace AzToolsFramework * @return A unique id for the new Link. */ LinkId CreateLink( - const TemplateId& linkTargetId, - const TemplateId& linkSourceId, + TemplateId linkTargetId, + TemplateId linkSourceId, const InstanceAlias& instanceAlias, const PrefabDomConstReference linkPatches, const LinkId& linkId = InvalidLinkId) override; @@ -181,14 +185,14 @@ namespace AzToolsFramework * @param templateId The id of the template to query. * @return The value of the dirty flag on the template. */ - bool IsTemplateDirty(const TemplateId& templateId) override; + bool IsTemplateDirty(TemplateId templateId) override; /** * Sets the dirty flag of the template to the value provided. * @param templateId The id of the template to flag. * @param dirty The new value of the dirty flag. */ - void SetTemplateDirtyFlag(const TemplateId& templateId, bool dirty) override; + void SetTemplateDirtyFlag(TemplateId templateId, bool dirty) override; bool AreDirtyTemplatesPresent(TemplateId rootTemplateId) override; @@ -200,20 +204,21 @@ namespace AzToolsFramework /** * Builds a new Prefab Template out of entities and instances and returns the first instance comprised of - * these entities and instances - * @param entities A vector of entities that will be used in the new instance. May be empty + * these entities and instances. + * @param entities A vector of entities that will be used in the new instance. May be empty. * @param instances A vector of Prefab Instances that will be nested in the new instance, will be consumed and moved. - * May be empty - * @param filePath the path to associate the template of the new instance to. + * May be empty. + * @param filePath The path to associate the template of the new instance to. * @param containerEntity The container entity for the prefab to be created. It will be created if a nullptr is provided. + * @param parent Reference of an instance the created instance will be placed under, if given. * @param shouldCreateLinks The flag indicating if links should be created between the templates of the instance * and its nested instances. - * @return A pointer to the newly created instance. nullptr on failure + * @return A pointer to the newly created instance. nullptr on failure. */ AZStd::unique_ptr CreatePrefab( const AZStd::vector& entities, AZStd::vector>&& instancesToConsume, AZ::IO::PathView filePath, AZStd::unique_ptr containerEntity = nullptr, - bool ShouldCreateLinks = true) override; + InstanceOptionalReference parent = AZStd::nullopt, bool shouldCreateLinks = true) override; PrefabDom& FindTemplateDom(TemplateId templateId) override; @@ -232,11 +237,26 @@ namespace AzToolsFramework * * @param templateId The id of the Template owning Instances to update. */ - void UpdatePrefabInstances(const TemplateId& templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt); + void UpdatePrefabInstances(TemplateId templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt); private: AZ_DISABLE_COPY_MOVE(PrefabSystemComponent); + /** + * Builds a new Prefab Template out of entities and instances and returns the first instance comprised of + * these entities and instances. + * @param entities A vector of entities that will be used in the new instance. May be empty. + * @param instances A vector of Prefab Instances that will be nested in the new instance, will be consumed and moved. + * May be empty. + * @param filePath The path to associate the template of the new instance to. + * @param instance Reference of a pointer to the newly created instance which needs initiation. + * @param shouldCreateLinks The flag indicating if links should be created between the templates of the instance + * and its nested instances. + */ + void CreatePrefab(const AZStd::vector& entities, + AZStd::vector>&& instancesToConsume, AZ::IO::PathView filePath, + AZStd::unique_ptr& instance, bool shouldCreateLinks); + /** * Updates all the linked Instances corresponding to the linkIds in the provided queue. * Queue gets populated with more linkId lists as linked instances are updated. Updating stops when the queue is empty. @@ -310,7 +330,7 @@ namespace AzToolsFramework * @param instance The instance that the template was created from. This needs to be editable for inserting linkId into it. * @return bool on whether the operation succeeded */ - bool GenerateLinksForNewTemplate(const TemplateId& newTemplateId, Instance& instance); + bool GenerateLinksForNewTemplate(TemplateId newTemplateId, Instance& instance); /** * Create a unique Template id for newly created Template. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h index 1f59088518..3baaf9ae12 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h @@ -29,28 +29,28 @@ namespace AzToolsFramework public: AZ_RTTI(PrefabSystemComponentInterface, "{8E95A029-67F9-4F74-895F-DDBFE29516A0}"); - virtual TemplateReference FindTemplate(const TemplateId& id) = 0; + virtual TemplateReference FindTemplate(TemplateId id) = 0; virtual LinkReference FindLink(const LinkId& id) = 0; virtual TemplateId AddTemplate(const AZ::IO::Path& filePath, PrefabDom prefabDom) = 0; virtual void UpdateTemplateFilePath(TemplateId templateId, const AZ::IO::PathView& filePath) = 0; - virtual void RemoveTemplate(const TemplateId& templateId) = 0; + virtual void RemoveTemplate(TemplateId templateId) = 0; virtual void RemoveAllTemplates() = 0; - virtual LinkId AddLink(const TemplateId& sourceTemplateId, const TemplateId& targetTemplateId, + virtual LinkId AddLink(TemplateId sourceTemplateId, TemplateId targetTemplateId, PrefabDomValue::MemberIterator& instanceIterator, InstanceOptionalReference instance) = 0; //creates a new Link virtual LinkId CreateLink( - const TemplateId& linkTargetId, const TemplateId& linkSourceId, const InstanceAlias& instanceAlias, + TemplateId linkTargetId, TemplateId linkSourceId, const InstanceAlias& instanceAlias, const PrefabDomConstReference linkPatches, const LinkId& linkId = InvalidLinkId) = 0; virtual void RemoveLink(const LinkId& linkId) = 0; virtual TemplateId GetTemplateIdFromFilePath(AZ::IO::PathView filePath) const = 0; - virtual bool IsTemplateDirty(const TemplateId& templateId) = 0; - virtual void SetTemplateDirtyFlag(const TemplateId& templateId, bool dirty) = 0; + virtual bool IsTemplateDirty(TemplateId templateId) = 0; + virtual void SetTemplateDirtyFlag(TemplateId templateId, bool dirty) = 0; //! Recursive function to check if the template is dirty or if any dirty templates are presents in the links of the template. //! @param rootTemplateId The id of the template provided as the beginning template to check the outgoing links. @@ -69,11 +69,14 @@ namespace AzToolsFramework virtual void UpdatePrefabTemplate(TemplateId templateId, const PrefabDom& updatedDom) = 0; virtual void PropagateTemplateChanges(TemplateId templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) = 0; - virtual AZStd::unique_ptr InstantiatePrefab(AZ::IO::PathView filePath) = 0; - virtual AZStd::unique_ptr InstantiatePrefab(const TemplateId& templateId) = 0; + virtual AZStd::unique_ptr InstantiatePrefab( + AZ::IO::PathView filePath, InstanceOptionalReference parent = AZStd::nullopt) = 0; + virtual AZStd::unique_ptr InstantiatePrefab( + TemplateId templateId, InstanceOptionalReference parent = AZStd::nullopt) = 0; virtual AZStd::unique_ptr CreatePrefab(const AZStd::vector& entities, AZStd::vector>&& instancesToConsume, AZ::IO::PathView filePath, - AZStd::unique_ptr containerEntity = nullptr, bool ShouldCreateLinks = true) = 0; + AZStd::unique_ptr containerEntity = nullptr, InstanceOptionalReference parent = AZStd::nullopt, + bool shouldCreateLinks = true) = 0; }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp index fe3555a853..385e9b149b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp @@ -33,7 +33,7 @@ namespace AzToolsFramework void PrefabUndoInstance::Capture( const PrefabDom& initialState, const PrefabDom& endState, - const TemplateId& templateId) + TemplateId templateId) { m_templateId = templateId; @@ -136,8 +136,8 @@ namespace AzToolsFramework } void PrefabUndoInstanceLink::Capture( - const TemplateId& targetId, - const TemplateId& sourceId, + TemplateId targetId, + TemplateId sourceId, const InstanceAlias& instanceAlias, PrefabDom linkPatches, const LinkId linkId) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h index 1b04852c37..0af94f86cc 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h @@ -49,7 +49,7 @@ namespace AzToolsFramework void Capture( const PrefabDom& initialState, const PrefabDom& endState, - const TemplateId& templateId); + TemplateId templateId); void Undo() override; void Redo() override; @@ -95,8 +95,8 @@ namespace AzToolsFramework //capture for add/remove void Capture( - const TemplateId& targetId, - const TemplateId& sourceId, + TemplateId targetId, + TemplateId sourceId, const InstanceAlias& instanceAlias, PrefabDom linkPatches = PrefabDom(), const LinkId linkId = InvalidLinkId); diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabCreateBenchmarks.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabCreateBenchmarks.cpp index 64c4058a47..8cc5e5f4d2 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabCreateBenchmarks.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabCreateBenchmarks.cpp @@ -72,7 +72,7 @@ namespace Benchmark AZStd::unique_ptr instance = m_prefabSystemComponent->CreatePrefab( entities , {} - , m_pathString); + , m_pathString); state.PauseTiming(); @@ -165,7 +165,7 @@ namespace Benchmark { nestedInstanceRoot = m_prefabSystemComponent->CreatePrefab( {}, - MakeInstanceList( AZStd::move(nestedInstanceRoot) ), + MakeInstanceList(AZStd::move(nestedInstanceRoot)), m_paths[instanceCounter]); } diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp index 0d95049e76..92a30b89f2 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp @@ -36,7 +36,7 @@ namespace Benchmark AZStd::unique_ptr enclosingInstance = m_prefabSystemComponent->CreatePrefab( {}, - MakeInstanceList( AZStd::move(nestedInstance) ), + MakeInstanceList(AZStd::move(nestedInstance)), enclosingTemplatePath); TemplateId templateToInstantiateId = enclosingInstance->GetTemplateId(); @@ -99,7 +99,7 @@ namespace Benchmark { currentInstanceRoot = m_prefabSystemComponent->CreatePrefab( {}, - MakeInstanceList( AZStd::move(currentInstanceRoot) ), + MakeInstanceList(AZStd::move(currentInstanceRoot)), m_paths[currentDepth - 1]); } @@ -151,7 +151,7 @@ namespace Benchmark { currentInstanceRoot = m_prefabSystemComponent->CreatePrefab( {}, - MakeInstanceList( AZStd::move(currentInstanceRoot) ), + MakeInstanceList(AZStd::move(currentInstanceRoot)), m_paths[currentDepth]); } @@ -214,7 +214,7 @@ namespace Benchmark currentInstanceRoot = m_prefabSystemComponent->CreatePrefab( {}, - MakeInstanceList( AZStd::move(currentInstanceRoot), AZStd::move(extraNestedInstance) ), + MakeInstanceList(AZStd::move(currentInstanceRoot), AZStd::move(extraNestedInstance)), m_paths[currentDepth]); } diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp index 14eee84b7d..72489b07a1 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp @@ -54,7 +54,7 @@ namespace UnitTest // Create a street prefab that nests the car and sportscar instances created above. The container entity will be created as part of the process. AZStd::unique_ptr streetInstance = - m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList( AZStd::move(carInstance), AZStd::move(sportsCarInstance) ), "test/street"); + m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList(AZStd::move(carInstance), AZStd::move(sportsCarInstance)), "test/street"); ASSERT_TRUE(streetInstance); m_instanceMap[StreetEntityName] = streetInstance.get(); diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstanceToTemplatePropagatorTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstanceToTemplatePropagatorTests.cpp index ebe35a5402..a08b0bf6c2 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstanceToTemplatePropagatorTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstanceToTemplatePropagatorTests.cpp @@ -320,7 +320,7 @@ namespace UnitTest Instance& addedInstance = *addedInstancePtr; //create a first instance where the instance will be removed - AZStd::unique_ptr firstInstance = m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList( AZStd::move(addedInstancePtr) ), "test/path"); + AZStd::unique_ptr firstInstance = m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList(AZStd::move(addedInstancePtr)), "test/path"); ASSERT_TRUE(firstInstance); //get added instance alias diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstantiateTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstantiateTests.cpp index 09aac8dcf5..cc8217a915 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstantiateTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstantiateTests.cpp @@ -44,11 +44,11 @@ namespace UnitTest ASSERT_TRUE(firstInstance); AZStd::unique_ptr secondInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(firstInstance) ), "test/path2"); + MakeInstanceList(AZStd::move(firstInstance)), "test/path2"); ASSERT_TRUE(secondInstance); AZStd::unique_ptr thirdInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(secondInstance) ), "test/path3"); + MakeInstanceList(AZStd::move(secondInstance)), "test/path3"); ASSERT_TRUE(thirdInstance); //Instantiate it diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDataUtils.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDataUtils.cpp index b805e224bf..55e3c158a1 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDataUtils.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDataUtils.cpp @@ -21,8 +21,8 @@ namespace UnitTest using namespace AzToolsFramework::Prefab; LinkData CreateLinkData( const InstanceData& instanceData, - const TemplateId& sourceTemplateId, - const TemplateId& targetTemplateId) + TemplateId sourceTemplateId, + TemplateId targetTemplateId) { LinkData newLinkData; newLinkData.m_instanceData = instanceData; diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDataUtils.h b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDataUtils.h index e3048469c5..0082ad5951 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDataUtils.h +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDataUtils.h @@ -17,8 +17,8 @@ namespace UnitTest { LinkData CreateLinkData( const InstanceData& instanceData, - const AzToolsFramework::Prefab::TemplateId& sourceTemplateId, - const AzToolsFramework::Prefab::TemplateId& targetTemplateId); + AzToolsFramework::Prefab::TemplateId sourceTemplateId, + AzToolsFramework::Prefab::TemplateId targetTemplateId); InstanceData CreateInstanceDataWithNoPatches( const AZStd::string& name, diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDomUtils.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDomUtils.cpp index 334f01fc3a..c71013320f 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDomUtils.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDomUtils.cpp @@ -56,7 +56,7 @@ namespace UnitTest } void ValidateInstances( - const TemplateId& templateId, + TemplateId templateId, const PrefabDomValue& expectedContent, const PrefabDomPath& contentPath, bool isContentAnInstance, @@ -204,7 +204,7 @@ namespace UnitTest } void ValidateEntitiesOfInstances( - const AzToolsFramework::Prefab::TemplateId& templateId, + AzToolsFramework::Prefab::TemplateId templateId, const AzToolsFramework::Prefab::PrefabDom& expectedPrefabDom, const AZStd::vector& entityAliases) { @@ -219,7 +219,7 @@ namespace UnitTest } void ValidateNestedInstancesOfInstances( - const AzToolsFramework::Prefab::TemplateId& templateId, + AzToolsFramework::Prefab::TemplateId templateId, const AzToolsFramework::Prefab::PrefabDom& expectedPrefabDom, const AZStd::vector& nestedInstanceAliases) { diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDomUtils.h b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDomUtils.h index f90a91ea3c..b1ba7fbca0 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDomUtils.h +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestDomUtils.h @@ -118,7 +118,7 @@ namespace UnitTest const PrefabDomValue& patches); void ValidateInstances( - const TemplateId& templateId, + TemplateId templateId, const PrefabDomValue& expectedContent, const PrefabDomPath& contentPath, bool isContentAnInstance = false, @@ -147,12 +147,12 @@ namespace UnitTest void ComparePrefabDomValues(PrefabDomValueConstReference valueA, PrefabDomValueConstReference valueB); void ValidateEntitiesOfInstances( - const AzToolsFramework::Prefab::TemplateId& templateId, + AzToolsFramework::Prefab::TemplateId templateId, const AzToolsFramework::Prefab::PrefabDom& expectedPrefabDom, const AZStd::vector& entityAliases); void ValidateNestedInstancesOfInstances( - const AzToolsFramework::Prefab::TemplateId& templateId, + AzToolsFramework::Prefab::TemplateId templateId, const AzToolsFramework::Prefab::PrefabDom& expectedPrefabDom, const AZStd::vector& nestedInstanceAliases); diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestUndoFixture.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestUndoFixture.cpp index cb44f9c401..2420b14d6c 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestUndoFixture.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestUndoFixture.cpp @@ -18,14 +18,14 @@ namespace UnitTest { //create two prefabs for test //create prefab 1 - firstInstance = AZStd::move(m_prefabSystemComponent->CreatePrefab({ }, {}, "test/path0")); + firstInstance = AZStd::move(m_prefabSystemComponent->CreatePrefab({}, {}, "test/path0")); ASSERT_TRUE(firstInstance); //get template id ownerId = firstInstance->GetTemplateId(); //create prefab 2 - secondInstance = AZStd::move(m_prefabSystemComponent->CreatePrefab({ }, {}, "test/path1")); + secondInstance = AZStd::move(m_prefabSystemComponent->CreatePrefab({}, {}, "test/path1")); ASSERT_TRUE(secondInstance); //get template id diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateInstancesTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateInstancesTests.cpp index baded6d43e..7427c06f43 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateInstancesTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateInstancesTests.cpp @@ -120,7 +120,7 @@ namespace UnitTest // Create an enclosing Template with 0 entities and 1 nested Instance. AZStd::unique_ptr nestedInstance1 = m_prefabSystemComponent->InstantiatePrefab(newNestedTemplateId); - AZStd::unique_ptr newEnclosingInstance = m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList( AZStd::move(nestedInstance1) ), PrefabMockFilePath); + AZStd::unique_ptr newEnclosingInstance = m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList(AZStd::move(nestedInstance1)), PrefabMockFilePath); TemplateId newEnclosingTemplateId = newEnclosingInstance->GetTemplateId(); EXPECT_TRUE(newEnclosingTemplateId != InvalidTemplateId); PrefabDom& newEnclosingTemplateDom = m_prefabSystemComponent->FindTemplateDom(newEnclosingTemplateId); @@ -284,7 +284,7 @@ namespace UnitTest AZStd::unique_ptr nestedInstance2 = m_prefabSystemComponent->InstantiatePrefab(newNestedTemplateId); AZStd::unique_ptr newEnclosingInstance = m_prefabSystemComponent->CreatePrefab( {}, - MakeInstanceList( AZStd::move(nestedInstance1), AZStd::move(nestedInstance2) ), + MakeInstanceList(AZStd::move(nestedInstance1), AZStd::move(nestedInstance2)), PrefabMockFilePath); TemplateId newEnclosingTemplateId = newEnclosingInstance->GetTemplateId(); EXPECT_TRUE(newEnclosingTemplateId != InvalidTemplateId); diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateTemplateTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateTemplateTests.cpp index 6f90e245f7..242c226c7e 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateTemplateTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateTemplateTests.cpp @@ -41,7 +41,7 @@ namespace UnitTest AZStd::unique_ptr wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr wheel2UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr axleInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(wheel1UnderAxle), AZStd::move(wheel2UnderAxle) ), AxlePrefabMockFilePath); + MakeInstanceList(AZStd::move(wheel1UnderAxle), AZStd::move(wheel2UnderAxle)), AxlePrefabMockFilePath); const TemplateId axleTemplateId = axleInstance->GetTemplateId(); const AZStd::vector wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId); PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId); @@ -51,7 +51,7 @@ namespace UnitTest AZStd::unique_ptr axle2UnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId); AZStd::unique_ptr spareWheelUnderCar = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr carInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(axle1UnderCar), AZStd::move(axle2UnderCar), AZStd::move(spareWheelUnderCar) ), CarPrefabMockFilePath); + MakeInstanceList(AZStd::move(axle1UnderCar), AZStd::move(axle2UnderCar), AZStd::move(spareWheelUnderCar)), CarPrefabMockFilePath); const TemplateId carTemplateId = carInstance->GetTemplateId(); const AZStd::vector axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId); const AZStd::vector wheelInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(wheelTemplateId); @@ -93,7 +93,7 @@ namespace UnitTest // Create an axle with 0 entities and 1 wheel instance. AZStd::unique_ptr wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr axleInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(wheel1UnderAxle) ), AxlePrefabMockFilePath); + MakeInstanceList(AZStd::move(wheel1UnderAxle)), AxlePrefabMockFilePath); const TemplateId axleTemplateId = axleInstance->GetTemplateId(); PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId); AZStd::vector wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId); @@ -105,7 +105,7 @@ namespace UnitTest AZStd::unique_ptr axle1UnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId); AZStd::unique_ptr axle2UnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId); AZStd::unique_ptr carInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(axle1UnderCar), AZStd::move(axle2UnderCar) ), CarPrefabMockFilePath); + MakeInstanceList(AZStd::move(axle1UnderCar), AZStd::move(axle2UnderCar)), CarPrefabMockFilePath); const TemplateId carTemplateId = carInstance->GetTemplateId(); const AZStd::vector axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId); PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId); @@ -151,7 +151,7 @@ namespace UnitTest // Create an axle with 0 entities and 1 wheel instance. AZStd::unique_ptr wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr axleInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(wheel1UnderAxle) ), AxlePrefabMockFilePath); + MakeInstanceList(AZStd::move(wheel1UnderAxle)), AxlePrefabMockFilePath); const TemplateId axleTemplateId = axleInstance->GetTemplateId(); PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId); const AZStd::vector wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId); @@ -159,7 +159,7 @@ namespace UnitTest // Create a car with 0 entities and 1 axle instance. AZStd::unique_ptr axleUnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId); AZStd::unique_ptr carInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(axleUnderCar) ), CarPrefabMockFilePath); + MakeInstanceList(AZStd::move(axleUnderCar)), CarPrefabMockFilePath); const TemplateId carTemplateId = carInstance->GetTemplateId(); const AZStd::vector axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId); PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId); @@ -205,7 +205,7 @@ namespace UnitTest // Create an axle with 0 entities and 1 wheel instance. AZStd::unique_ptr wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr axleInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(wheel1UnderAxle) ), AxlePrefabMockFilePath); + MakeInstanceList(AZStd::move(wheel1UnderAxle)), AxlePrefabMockFilePath); const TemplateId axleTemplateId = axleInstance->GetTemplateId(); PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId); const AZStd::vector wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId); @@ -213,7 +213,7 @@ namespace UnitTest // Create a car with 0 entities and 1 axle instance. AZStd::unique_ptr axleUnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId); AZStd::unique_ptr carInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(axleUnderCar) ), CarPrefabMockFilePath); + MakeInstanceList(AZStd::move(axleUnderCar)), CarPrefabMockFilePath); const TemplateId carTemplateId = carInstance->GetTemplateId(); const AZStd::vector axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId); PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId); @@ -253,7 +253,7 @@ namespace UnitTest AZStd::unique_ptr wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr wheel2UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr axleInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(wheel1UnderAxle), AZStd::move(wheel2UnderAxle) ), + MakeInstanceList(AZStd::move(wheel1UnderAxle), AZStd::move(wheel2UnderAxle) ), AxlePrefabMockFilePath); const TemplateId axleTemplateId = axleInstance->GetTemplateId(); PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId); @@ -265,7 +265,7 @@ namespace UnitTest // Create a car with 0 entities and 1 axle instance. AZStd::unique_ptr axle1UnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId); AZStd::unique_ptr carInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(axle1UnderCar) ), CarPrefabMockFilePath); + MakeInstanceList(AZStd::move(axle1UnderCar)), CarPrefabMockFilePath); const TemplateId carTemplateId = carInstance->GetTemplateId(); const AZStd::vector axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId); PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId); @@ -320,7 +320,7 @@ namespace UnitTest // Create an axle with 0 entities and 1 wheel instance. AZStd::unique_ptr wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr axleInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(wheel1UnderAxle) ), AxlePrefabMockFilePath); + MakeInstanceList(AZStd::move(wheel1UnderAxle)), AxlePrefabMockFilePath); const TemplateId axleTemplateId = axleInstance->GetTemplateId(); PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId); const AZStd::vector wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId); @@ -328,7 +328,7 @@ namespace UnitTest // Create a car with 0 entities and 1 axle instance. AZStd::unique_ptr axleUnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId); AZStd::unique_ptr carInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(axleUnderCar) ), CarPrefabMockFilePath); + MakeInstanceList(AZStd::move(axleUnderCar)), CarPrefabMockFilePath); const TemplateId carTemplateId = carInstance->GetTemplateId(); const AZStd::vector axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId); PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId); @@ -381,7 +381,7 @@ namespace UnitTest // Create an axle with 0 entities and 1 wheel instance. AZStd::unique_ptr wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId); AZStd::unique_ptr axleInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(wheel1UnderAxle) ), AxlePrefabMockFilePath); + MakeInstanceList(AZStd::move(wheel1UnderAxle)), AxlePrefabMockFilePath); const TemplateId axleTemplateId = axleInstance->GetTemplateId(); PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId); const AZStd::vector wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId); @@ -389,7 +389,7 @@ namespace UnitTest // Create a car with 0 entities and 1 axle instance. AZStd::unique_ptr axleUnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId); AZStd::unique_ptr carInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(axleUnderCar) ), CarPrefabMockFilePath); + MakeInstanceList(AZStd::move(axleUnderCar)), CarPrefabMockFilePath); const TemplateId carTemplateId = carInstance->GetTemplateId(); const AZStd::vector axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId); PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId); diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateWithPatchesTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateWithPatchesTests.cpp index c17763f778..1fa638bc29 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateWithPatchesTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateWithPatchesTests.cpp @@ -68,7 +68,7 @@ namespace UnitTest // Create a car with 0 entities and 1 axle instance. AZStd::unique_ptr axleUnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId); AZStd::unique_ptr carInstance = m_prefabSystemComponent->CreatePrefab({}, - MakeInstanceList( AZStd::move(axleUnderCar) ), CarPrefabMockFilePath); + MakeInstanceList(AZStd::move(axleUnderCar)), CarPrefabMockFilePath); const TemplateId carTemplateId = carInstance->GetTemplateId(); const AZStd::vector axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId); PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId); diff --git a/Code/Tools/SerializeContextTools/SliceConverter.cpp b/Code/Tools/SerializeContextTools/SliceConverter.cpp index df4f394cc5..c815af3b7a 100644 --- a/Code/Tools/SerializeContextTools/SliceConverter.cpp +++ b/Code/Tools/SerializeContextTools/SliceConverter.cpp @@ -558,7 +558,7 @@ namespace AZ AZStd::string instanceAlias = GetInstanceAlias(instance); // Create a new unmodified prefab Instance for the nested slice instance. - auto nestedInstance = AZStd::make_unique(); + auto nestedInstance = AZStd::make_unique(AZStd::move(instanceAlias)); AzToolsFramework::Prefab::Instance::EntityList newEntities; if (!AzToolsFramework::Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom( *nestedInstance, newEntities, nestedTemplate->get().GetPrefabDom())) @@ -742,7 +742,7 @@ namespace AZ instanceToTemplateInterface->GenerateDomForInstance(topLevelInstanceDomBefore, *topLevelInstance); // Use the deterministic instance alias for this new instance - AzToolsFramework::Prefab::Instance& addedInstance = topLevelInstance->AddInstance(AZStd::move(nestedInstance), instanceAlias); + AzToolsFramework::Prefab::Instance& addedInstance = topLevelInstance->AddInstance(AZStd::move(nestedInstance)); AzToolsFramework::Prefab::PrefabDom topLevelInstanceDomAfter; instanceToTemplateInterface->GenerateDomForInstance(topLevelInstanceDomAfter, *topLevelInstance); From 18b947fd0016146f1399d7e5bba3992a023cf979 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 1 Oct 2021 12:11:55 -0500 Subject: [PATCH 47/50] Changed the AssetManager DispatchEvents function to continously pump the (#4432) AssetBus of queued functions until empty. This replicates the old behavior of the EBusQueuePolicy::Execute function that would continue to execute functions if new ones were added during the execution of the current queue. Split the TestFixture class from the AssetHandler and EBus handler for the DynamicSliceInstanceSpawnerTests and PrefabInstanceSpawnerTest. This avoids the AssetMananager destructor from deleting the test fixture if the call to UnregisterHandler is ever removed. This also allows the memory allocators to get online earlier. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../AzCore/AzCore/Asset/AssetManager.cpp | 7 +- .../DynamicSliceInstanceSpawnerTests.cpp | 143 ++++++++++-------- .../Code/Tests/PrefabInstanceSpawnerTests.cpp | 143 ++++++++++-------- Gems/Vegetation/Code/Tests/VegetationTest.h | 25 ++- 4 files changed, 180 insertions(+), 138 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp index 8eb620f69e..06bb0b0cac 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp +++ b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp @@ -551,8 +551,6 @@ namespace AZ { PrepareShutDown(); - DispatchEvents(); - // Acquire the asset lock to make sure nobody else is trying to do anything fancy with assets AZStd::scoped_lock assetLock(m_assetMutex); @@ -575,7 +573,10 @@ namespace AZ { AZ_PROFILE_FUNCTION(AzCore); AssetManagerNotificationBus::Broadcast(&AssetManagerNotificationBus::Events::OnAssetEventsDispatchBegin); - AssetBus::ExecuteQueuedEvents(); + while (AssetBus::QueuedEventCount()) + { + AssetBus::ExecuteQueuedEvents(); + } AssetManagerNotificationBus::Broadcast(&AssetManagerNotificationBus::Events::OnAssetEventsDispatchEnd); } diff --git a/Gems/Vegetation/Code/Tests/DynamicSliceInstanceSpawnerTests.cpp b/Gems/Vegetation/Code/Tests/DynamicSliceInstanceSpawnerTests.cpp index 9838a7b6a1..26d8028522 100644 --- a/Gems/Vegetation/Code/Tests/DynamicSliceInstanceSpawnerTests.cpp +++ b/Gems/Vegetation/Code/Tests/DynamicSliceInstanceSpawnerTests.cpp @@ -50,80 +50,25 @@ namespace UnitTest } }; - // To test Dynamic Slice spawning, we need to mock up enough of the asset management system and the dynamic slice - // asset handling to pretend like we're loading/unloading dynamic slices successfully. - class DynamicSliceInstanceSpawnerTests - : public VegetationComponentTests - , public UnitTest::SetRestoreFileIOBaseRAII - , public Vegetation::DescriptorNotificationBus::Handler + class DynamicSliceAssetCatalogAndHandler + : public Vegetation::DescriptorNotificationBus::Handler , public AZ::Data::AssetCatalogRequestBus::Handler , public AZ::Data::AssetHandler , public AZ::Data::AssetCatalog , public AzFramework::SliceGameEntityOwnershipServiceRequestBus::Handler { public: - DynamicSliceInstanceSpawnerTests() - : UnitTest::SetRestoreFileIOBaseRAII(m_fileIOMock) + DynamicSliceAssetCatalogAndHandler() { - AZ::IO::MockFileIOBase::InstallDefaultReturns(m_fileIOMock); - } - - void RegisterComponentDescriptors() override - { - m_app.RegisterComponentDescriptor(MockDynamicSliceInstanceVegetationSystemComponent::CreateDescriptor()); - } - - void SetUp() override - { - VegetationComponentTests::SetUp(); - - // Create a real Asset Mananger, and point to ourselves as the handler for DynamicSliceAsset. - AZ::AllocatorInstance::Create(); - AZ::AllocatorInstance::Create(); - - - // Initialize the job manager with 1 thread for the AssetManager to use. - AZ::JobManagerDesc jobDesc; - AZ::JobManagerThreadDesc threadDesc; - jobDesc.m_workerThreads.push_back(threadDesc); - m_jobManager = aznew AZ::JobManager(jobDesc); - m_jobContext = aznew AZ::JobContext(*m_jobManager); - AZ::JobContext::SetGlobalContext(m_jobContext); - - AZ::Data::AssetManager::Descriptor descriptor; - AZ::Data::AssetManager::Create(descriptor); - AZ::Data::AssetManager::Instance().RegisterHandler(this, AZ::AzTypeInfo::Uuid()); - AZ::Data::AssetManager::Instance().RegisterCatalog(this, AZ::AzTypeInfo::Uuid()); - - m_app.RegisterComponentDescriptor(AZ::SliceComponent::CreateDescriptor()); - // Intercept messages for finding assets by name and creating/destroying slices. AZ::Data::AssetCatalogRequestBus::Handler::BusConnect(); AzFramework::SliceGameEntityOwnershipServiceRequestBus::Handler::BusConnect(); } - void TearDown() override + ~DynamicSliceAssetCatalogAndHandler() { - // Give the AssetManager a chance to fire off any lingering events and perform cleanup for any - // dynamic slice assets we loaded. - AZ::Data::AssetManager::Instance().DispatchEvents(); - AzFramework::SliceGameEntityOwnershipServiceRequestBus::Handler::BusDisconnect(); - AZ::Data::AssetManager::Instance().UnregisterCatalog(this); - AZ::Data::AssetManager::Instance().UnregisterHandler(this); - AZ::Data::AssetCatalogRequestBus::Handler::BusDisconnect(); - - AZ::Data::AssetManager::Destroy(); - - AZ::JobContext::SetGlobalContext(nullptr); - delete m_jobContext; - delete m_jobManager; - - AZ::AllocatorInstance::Destroy(); - AZ::AllocatorInstance::Destroy(); - - VegetationComponentTests::TearDown(); } // Helper methods: @@ -207,7 +152,7 @@ namespace UnitTest AZStd::string GetAssetPathById(const AZ::Data::AssetId& /*id*/) override { return m_assetPath; } AZ::Data::AssetId GetAssetIdByPath(const char* /*path*/, const AZ::Data::AssetType& /*typeToRegister*/, bool /*autoRegisterIfNotFound*/) override { return m_assetId; } AZ::Data::AssetInfo GetAssetInfoById(const AZ::Data::AssetId& /*id*/) override - { + { AZ::Data::AssetInfo assetInfo; assetInfo.m_assetId = m_assetId; assetInfo.m_assetType = AZ::AzTypeInfo::Uuid(); @@ -244,9 +189,77 @@ namespace UnitTest AZStd::string m_assetPath; AZ::Data::AssetId m_assetId; int m_numOnLoadedCalls = 0; + }; + // To test Dynamic Slice spawning, we need to mock up enough of the asset management system and the dynamic slice + // asset handling to pretend like we're loading/unloading dynamic slices successfully. + class DynamicSliceInstanceSpawnerTests + : public VegetationComponentTests + { + public: + DynamicSliceInstanceSpawnerTests() + : m_restoreFileIO(m_fileIOMock) + { + AZ::IO::MockFileIOBase::InstallDefaultReturns(m_fileIOMock); + } + void SetUp() override + { + VegetationComponentTests::SetUp(); + + // Create a real Asset Mananger, and point to ourselves as the handler for DynamicSliceAsset. + AZ::AllocatorInstance::Create(); + AZ::AllocatorInstance::Create(); + + // Initialize the job manager with 1 thread for the AssetManager to use. + AZ::JobManagerDesc jobDesc; + AZ::JobManagerThreadDesc threadDesc; + jobDesc.m_workerThreads.push_back(threadDesc); + m_jobManager = aznew AZ::JobManager(jobDesc); + m_jobContext = aznew AZ::JobContext(*m_jobManager); + AZ::JobContext::SetGlobalContext(m_jobContext); + + AZ::Data::AssetManager::Descriptor descriptor; + AZ::Data::AssetManager::Create(descriptor); + m_testHandler = AZStd::make_unique(); + AZ::Data::AssetManager::Instance().RegisterHandler(m_testHandler.get(), AZ::AzTypeInfo::Uuid()); + AZ::Data::AssetManager::Instance().RegisterCatalog(m_testHandler.get(), AZ::AzTypeInfo::Uuid()); + + m_app.RegisterComponentDescriptor(AZ::SliceComponent::CreateDescriptor()); + } + + void TearDown() override + { + // Clear out the list of queued AssetBus Events before unregistering the AssetHandler + // to make sure pending references to Asset instances are cleared + AZ::Data::AssetManager::Instance().DispatchEvents(); + AZ::Data::AssetManager::Instance().UnregisterHandler(m_testHandler.get()); + AZ::Data::AssetManager::Instance().UnregisterCatalog(m_testHandler.get()); + AZ::Data::AssetManager::Destroy(); + + m_testHandler.reset(); + + AZ::JobContext::SetGlobalContext(nullptr); + delete m_jobContext; + delete m_jobManager; + + AZ::AllocatorInstance::Destroy(); + AZ::AllocatorInstance::Destroy(); + + VegetationComponentTests::TearDown(); + } + + void RegisterComponentDescriptors() override + { + m_app.RegisterComponentDescriptor(MockDynamicSliceInstanceVegetationSystemComponent::CreateDescriptor()); + } + + protected: + AZStd::unique_ptr m_testHandler; + + private: AZ::JobManager* m_jobManager{ nullptr }; AZ::JobContext* m_jobContext{ nullptr }; + SetRestoreFileIOBaseRAII m_restoreFileIO; ::testing::NiceMock m_fileIOMock; }; @@ -276,7 +289,7 @@ namespace UnitTest Vegetation::DynamicSliceInstanceSpawner instanceSpawner2; // Give the second instance spawner a non-default asset reference. - CreateAndSetMockAsset(instanceSpawner2, AZ::Uuid::CreateRandom(), "test"); + m_testHandler->CreateAndSetMockAsset(instanceSpawner2, AZ::Uuid::CreateRandom(), "test"); // The test is written this way because only the == operator is overloaded. EXPECT_TRUE(!(instanceSpawner1 == instanceSpawner2)); @@ -292,14 +305,14 @@ namespace UnitTest EXPECT_TRUE(instanceSpawner.HasEmptyAssetReferences()); // This will test the asset load. - CreateAndSetMockAsset(instanceSpawner, AZ::Uuid::CreateRandom(), "test"); + m_testHandler->CreateAndSetMockAsset(instanceSpawner, AZ::Uuid::CreateRandom(), "test"); // Test the asset unload works too. - Vegetation::DescriptorNotificationBus::Handler::BusConnect(&instanceSpawner); + m_testHandler->Vegetation::DescriptorNotificationBus::Handler::BusConnect(&instanceSpawner); instanceSpawner.UnloadAssets(); EXPECT_FALSE(instanceSpawner.IsLoaded()); EXPECT_FALSE(instanceSpawner.IsSpawnable()); - Vegetation::DescriptorNotificationBus::Handler::BusDisconnect(); + m_testHandler->Vegetation::DescriptorNotificationBus::Handler::BusDisconnect(); } TEST_F(DynamicSliceInstanceSpawnerTests, CreateAndDestroyInstance) @@ -308,7 +321,7 @@ namespace UnitTest Vegetation::DynamicSliceInstanceSpawner instanceSpawner; - CreateAndSetMockAsset(instanceSpawner, AZ::Uuid::CreateRandom(), "test"); + m_testHandler->CreateAndSetMockAsset(instanceSpawner, AZ::Uuid::CreateRandom(), "test"); instanceSpawner.OnRegisterUniqueDescriptor(); diff --git a/Gems/Vegetation/Code/Tests/PrefabInstanceSpawnerTests.cpp b/Gems/Vegetation/Code/Tests/PrefabInstanceSpawnerTests.cpp index b0d88f2d63..3398dba20f 100644 --- a/Gems/Vegetation/Code/Tests/PrefabInstanceSpawnerTests.cpp +++ b/Gems/Vegetation/Code/Tests/PrefabInstanceSpawnerTests.cpp @@ -51,76 +51,21 @@ namespace UnitTest } }; - // To test prefab spawning, we need to mock up enough of the asset management system and the spawnable - // asset handling to pretend like we're loading/unloading spawnables successfully. - class PrefabInstanceSpawnerTests - : public VegetationComponentTests - , public UnitTest::SetRestoreFileIOBaseRAII - , public Vegetation::DescriptorNotificationBus::Handler + class PrefabInstanceHandlerAndCatalog + : public Vegetation::DescriptorNotificationBus::Handler , public AZ::Data::AssetCatalogRequestBus::Handler , public AZ::Data::AssetHandler , public AZ::Data::AssetCatalog { public: - PrefabInstanceSpawnerTests() - : UnitTest::SetRestoreFileIOBaseRAII(m_fileIOMock) + PrefabInstanceHandlerAndCatalog() { - AZ::IO::MockFileIOBase::InstallDefaultReturns(m_fileIOMock); - AzFramework::MockSpawnableEntitiesInterface::InstallDefaultReturns(m_spawnableEntitiesInterfaceMock); - } - - void RegisterComponentDescriptors() override - { - m_app.RegisterComponentDescriptor(MockPrefabInstanceVegetationSystemComponent::CreateDescriptor()); - } - - void SetUp() override - { - VegetationComponentTests::SetUp(); - - // Create a real Asset Mananger, and point to ourselves as the handler for Spawnable. - AZ::AllocatorInstance::Create(); - AZ::AllocatorInstance::Create(); - - - // Initialize the job manager with 1 thread for the AssetManager to use. - AZ::JobManagerDesc jobDesc; - AZ::JobManagerThreadDesc threadDesc; - jobDesc.m_workerThreads.push_back(threadDesc); - m_jobManager = aznew AZ::JobManager(jobDesc); - m_jobContext = aznew AZ::JobContext(*m_jobManager); - AZ::JobContext::SetGlobalContext(m_jobContext); - - AZ::Data::AssetManager::Descriptor descriptor; - AZ::Data::AssetManager::Create(descriptor); - AZ::Data::AssetManager::Instance().RegisterHandler(this, AZ::AzTypeInfo::Uuid()); - AZ::Data::AssetManager::Instance().RegisterCatalog(this, AZ::AzTypeInfo::Uuid()); - - // Intercept messages for finding assets by name. AZ::Data::AssetCatalogRequestBus::Handler::BusConnect(); } - void TearDown() override + ~PrefabInstanceHandlerAndCatalog() { - // Give the AssetManager a chance to fire off any lingering events and perform cleanup for any - // spawnable assets we loaded. - AZ::Data::AssetManager::Instance().DispatchEvents(); - - AZ::Data::AssetManager::Instance().UnregisterCatalog(this); - AZ::Data::AssetManager::Instance().UnregisterHandler(this); - AZ::Data::AssetCatalogRequestBus::Handler::BusDisconnect(); - - AZ::Data::AssetManager::Destroy(); - - AZ::JobContext::SetGlobalContext(nullptr); - delete m_jobContext; - delete m_jobManager; - - AZ::AllocatorInstance::Destroy(); - AZ::AllocatorInstance::Destroy(); - - VegetationComponentTests::TearDown(); } // Helper methods: @@ -227,9 +172,79 @@ namespace UnitTest AZStd::string m_assetPath; AZ::Data::AssetId m_assetId; int m_numOnLoadedCalls = 0; + }; + // To test Dynamic Slice spawning, we need to mock up enough of the asset management system and the dynamic slice + // asset handling to pretend like we're loading/unloading dynamic slices successfully. + class PrefabInstanceSpawnerTests + : public VegetationComponentTests + { + public: + PrefabInstanceSpawnerTests() + : m_restoreFileIO(m_fileIOMock) + { + AZ::IO::MockFileIOBase::InstallDefaultReturns(m_fileIOMock); + AzFramework::MockSpawnableEntitiesInterface::InstallDefaultReturns(m_spawnableEntitiesInterfaceMock); + } + + void SetUp() override + { + VegetationComponentTests::SetUp(); + + // Create a real Asset Mananger, and point to ourselves as the handler for DynamicSliceAsset. + AZ::AllocatorInstance::Create(); + AZ::AllocatorInstance::Create(); + + // Initialize the job manager with 1 thread for the AssetManager to use. + AZ::JobManagerDesc jobDesc; + AZ::JobManagerThreadDesc threadDesc; + jobDesc.m_workerThreads.push_back(threadDesc); + m_jobManager = aznew AZ::JobManager(jobDesc); + m_jobContext = aznew AZ::JobContext(*m_jobManager); + AZ::JobContext::SetGlobalContext(m_jobContext); + + AZ::Data::AssetManager::Descriptor descriptor; + AZ::Data::AssetManager::Create(descriptor); + m_testHandler = AZStd::make_unique(); + AZ::Data::AssetManager::Instance().RegisterHandler(m_testHandler.get(), AZ::AzTypeInfo::Uuid()); + AZ::Data::AssetManager::Instance().RegisterCatalog(m_testHandler.get(), AZ::AzTypeInfo::Uuid()); + + m_app.RegisterComponentDescriptor(AZ::SliceComponent::CreateDescriptor()); + } + + void TearDown() override + { + // Clear out the list of queued AssetBus Events before unregistering the AssetHandler + // to make sure pending references to Asset instances are cleared + AZ::Data::AssetManager::Instance().DispatchEvents(); + AZ::Data::AssetManager::Instance().UnregisterHandler(m_testHandler.get()); + AZ::Data::AssetManager::Instance().UnregisterCatalog(m_testHandler.get()); + AZ::Data::AssetManager::Destroy(); + + m_testHandler.reset(); + + AZ::JobContext::SetGlobalContext(nullptr); + delete m_jobContext; + delete m_jobManager; + + AZ::AllocatorInstance::Destroy(); + AZ::AllocatorInstance::Destroy(); + + VegetationComponentTests::TearDown(); + } + + void RegisterComponentDescriptors() override + { + m_app.RegisterComponentDescriptor(MockPrefabInstanceVegetationSystemComponent::CreateDescriptor()); + } + + protected: + AZStd::unique_ptr m_testHandler; + + private: AZ::JobManager* m_jobManager{ nullptr }; AZ::JobContext* m_jobContext{ nullptr }; + SetRestoreFileIOBaseRAII m_restoreFileIO; ::testing::NiceMock m_fileIOMock; ::testing::NiceMock m_spawnableEntitiesInterfaceMock; }; @@ -259,7 +274,7 @@ namespace UnitTest Vegetation::PrefabInstanceSpawner instanceSpawner2; // Give the second instance spawner a non-default asset reference. - CreateAndSetMockAsset(instanceSpawner2, AZ::Uuid::CreateRandom(), "test"); + m_testHandler->CreateAndSetMockAsset(instanceSpawner2, AZ::Uuid::CreateRandom(), "test"); // The test is written this way because only the == operator is overloaded. EXPECT_TRUE(!(instanceSpawner1 == instanceSpawner2)); @@ -275,14 +290,14 @@ namespace UnitTest EXPECT_TRUE(instanceSpawner.HasEmptyAssetReferences()); // This will test the asset load. - CreateAndSetMockAsset(instanceSpawner, AZ::Uuid::CreateRandom(), "test"); + m_testHandler->CreateAndSetMockAsset(instanceSpawner, AZ::Uuid::CreateRandom(), "test"); // Test the asset unload works too. - Vegetation::DescriptorNotificationBus::Handler::BusConnect(&instanceSpawner); + m_testHandler->Vegetation::DescriptorNotificationBus::Handler::BusConnect(&instanceSpawner); instanceSpawner.UnloadAssets(); EXPECT_FALSE(instanceSpawner.IsLoaded()); EXPECT_FALSE(instanceSpawner.IsSpawnable()); - Vegetation::DescriptorNotificationBus::Handler::BusDisconnect(); + m_testHandler->Vegetation::DescriptorNotificationBus::Handler::BusDisconnect(); } TEST_F(PrefabInstanceSpawnerTests, CreateAndDestroyInstance) @@ -291,7 +306,7 @@ namespace UnitTest Vegetation::PrefabInstanceSpawner instanceSpawner; - CreateAndSetMockAsset(instanceSpawner, AZ::Uuid::CreateRandom(), "test"); + m_testHandler->CreateAndSetMockAsset(instanceSpawner, AZ::Uuid::CreateRandom(), "test"); instanceSpawner.OnRegisterUniqueDescriptor(); diff --git a/Gems/Vegetation/Code/Tests/VegetationTest.h b/Gems/Vegetation/Code/Tests/VegetationTest.h index cf7c9b70a1..2ae8ac9cca 100644 --- a/Gems/Vegetation/Code/Tests/VegetationTest.h +++ b/Gems/Vegetation/Code/Tests/VegetationTest.h @@ -21,21 +21,34 @@ namespace UnitTest { class VegetationComponentTests - : public ::testing::Test + : public ScopedAllocatorSetupFixture { protected: + VegetationComponentTests() + : ScopedAllocatorSetupFixture( + []() { + AZ::SystemAllocator::Descriptor desc; + desc.m_heap.m_fixedMemoryBlocksByteSize[0] = 20 * 1024 * 1024; + desc.m_stackRecordLevels = 20; + return desc; + }() + ) + { + } + AZ::ComponentApplication m_app; virtual void RegisterComponentDescriptors() {} void SetUp() override { - AZ::ComponentApplication::Descriptor appDesc; - appDesc.m_memoryBlocksByteSize = 20 * 1024 * 1024; - appDesc.m_recordingMode = AZ::Debug::AllocationRecords::RECORD_NO_RECORDS; - appDesc.m_stackRecordLevels = 20; + if (AZ::Debug::AllocationRecords* records = AZ::AllocatorInstance::GetAllocator().GetRecords(); + records != nullptr) + { + records->SetMode(AZ::Debug::AllocationRecords::RECORD_NO_RECORDS); + } - m_app.Create(appDesc); + m_app.Create({}); RegisterComponentDescriptors(); } From 799ab8585bdf7ffa95b32d207bc68953272bec54 Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Fri, 1 Oct 2021 12:24:57 -0700 Subject: [PATCH 48/50] Update MaterialEditor launcher to use platform traits for executable extensions (#4429) Signed-off-by: Steve Pham --- .../Code/Source/Material/EditorMaterialSystemComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp index 83ddbf46c5..a6b595940f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp @@ -137,7 +137,7 @@ namespace AZ arguments.append(QString("--project-path=%1").arg(projectPath.c_str())); } - AtomToolsFramework::LaunchTool("MaterialEditor", ".exe", arguments); + AtomToolsFramework::LaunchTool("MaterialEditor", AZ_TRAIT_OS_EXECUTABLE_EXTENSION, arguments); } void EditorMaterialSystemComponent::OpenMaterialInspector( From 7018f16088c36377b88f86f79c6de3d03cb81beb Mon Sep 17 00:00:00 2001 From: Mikhail Naumov <82239319+AMZN-mnaumov@users.noreply.github.com> Date: Fri, 1 Oct 2021 15:16:45 -0500 Subject: [PATCH 49/50] Fixing undo/redo not updating transform pivot point (#4375) * Fixing undo/redo not updating transform pivot point Signed-off-by: Mikhail Naumov * PR feedback Signed-off-by: Mikhail Naumov * PR feedback Signed-off-by: Mikhail Naumov * fixing non-redo operations to still use batching (fixes some tests) Signed-off-by: Mikhail Naumov --- .../Prefab/Instance/InstanceToTemplateInterface.h | 3 ++- .../Instance/InstanceToTemplatePropagator.cpp | 4 ++-- .../Instance/InstanceToTemplatePropagator.h | 2 +- .../Prefab/Instance/InstanceUpdateExecutor.cpp | 7 ++++++- .../Prefab/Instance/InstanceUpdateExecutor.h | 2 +- .../Instance/InstanceUpdateExecutorInterface.h | 2 +- .../Prefab/PrefabPublicHandler.cpp | 2 +- .../Prefab/PrefabSystemComponent.cpp | 8 ++++---- .../Prefab/PrefabSystemComponent.h | 7 +++++-- .../Prefab/PrefabSystemComponentInterface.h | 2 +- .../AzToolsFramework/Prefab/PrefabUndo.cpp | 15 ++++++++++----- .../AzToolsFramework/Prefab/PrefabUndo.h | 1 + .../AzToolsFramework/Prefab/PrefabUndoHelpers.cpp | 2 +- 13 files changed, 36 insertions(+), 21 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplateInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplateInterface.h index b944ef159a..a8c717d6b0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplateInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplateInterface.h @@ -46,10 +46,11 @@ namespace AzToolsFramework //! Updates the template links (updating instances) for the given template and triggers propagation on its instances. //! @param providedPatch The patch to apply to the template. //! @param templateId The id of the template to update. + //! @param immediate An optional flag whether to apply the patch immediately (needed for Undo/Redos) or wait until next system tick. //! @param instanceToExclude An optional reference to an instance of the template being updated that should not be refreshes as part of propagation. //! Defaults to nullopt, which means that all instances will be refreshed. //! @return True if the template was patched correctly, false if the operation failed. - virtual bool PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) = 0; + virtual bool PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId, bool immediate = false, InstanceOptionalReference instanceToExclude = AZStd::nullopt) = 0; virtual void ApplyPatchesToInstance(const AZ::EntityId& entityId, PrefabDom& patches, const Instance& instanceToAddPatches) = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp index 6b281bcbae..73acb9b8a4 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp @@ -156,7 +156,7 @@ namespace AzToolsFramework } } - bool InstanceToTemplatePropagator::PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId, InstanceOptionalReference instanceToExclude) + bool InstanceToTemplatePropagator::PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId, bool immediate, InstanceOptionalReference instanceToExclude) { PrefabDom& templateDomReference = m_prefabSystemComponentInterface->FindTemplateDom(templateId); @@ -178,7 +178,7 @@ namespace AzToolsFramework (result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::PartialSkip), "Some of the patches were not successfully applied."); m_prefabSystemComponentInterface->SetTemplateDirtyFlag(templateId, true); - m_prefabSystemComponentInterface->PropagateTemplateChanges(templateId, instanceToExclude); + m_prefabSystemComponentInterface->PropagateTemplateChanges(templateId, immediate, instanceToExclude); return true; } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.h index 75acb410c9..80fe7de8d5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.h @@ -33,7 +33,7 @@ namespace AzToolsFramework InstanceOptionalReference GetTopMostInstanceInHierarchy(AZ::EntityId entityId) override; - bool PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) override; + bool PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId, bool immediate = false, InstanceOptionalReference instanceToExclude = AZStd::nullopt) override; void ApplyPatchesToInstance(const AZ::EntityId& entityId, PrefabDom& patches, const Instance& instanceToAddPatches) override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp index 9ef74167a6..feea3ce25b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp @@ -52,7 +52,7 @@ namespace AzToolsFramework AZ::Interface::Unregister(this); } - void InstanceUpdateExecutor::AddTemplateInstancesToQueue(TemplateId instanceTemplateId, InstanceOptionalReference instanceToExclude) + void InstanceUpdateExecutor::AddTemplateInstancesToQueue(TemplateId instanceTemplateId, bool immediate, InstanceOptionalReference instanceToExclude) { auto findInstancesResult = m_templateInstanceMapperInterface->FindInstancesOwnedByTemplate(instanceTemplateId); @@ -79,6 +79,11 @@ namespace AzToolsFramework m_instancesUpdateQueue.emplace_back(instance); } } + + if (immediate) + { + UpdateTemplateInstancesInQueue(); + } } void InstanceUpdateExecutor::RemoveTemplateInstanceFromQueue(const Instance* instance) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.h index ee461eae88..de2b483c4d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.h @@ -31,7 +31,7 @@ namespace AzToolsFramework explicit InstanceUpdateExecutor(int instanceCountToUpdateInBatch = 0); - void AddTemplateInstancesToQueue(TemplateId instanceTemplateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) override; + void AddTemplateInstancesToQueue(TemplateId instanceTemplateId, bool immediate = false, InstanceOptionalReference instanceToExclude = AZStd::nullopt) override; bool UpdateTemplateInstancesInQueue() override; virtual void RemoveTemplateInstanceFromQueue(const Instance* instance) override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutorInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutorInterface.h index 8ad032e1d0..3b894efd21 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutorInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutorInterface.h @@ -23,7 +23,7 @@ namespace AzToolsFramework virtual ~InstanceUpdateExecutorInterface() = default; // Add all Instances of Template with given Id into a queue for updating them later. - virtual void AddTemplateInstancesToQueue(TemplateId instanceTemplateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) = 0; + virtual void AddTemplateInstancesToQueue(TemplateId instanceTemplateId, bool immediate = false, InstanceOptionalReference instanceToExclude = AZStd::nullopt) = 0; // Update Instances in the waiting queue. virtual bool UpdateTemplateInstancesInQueue() = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 41538d54e8..038f36eac9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -1041,7 +1041,7 @@ namespace AzToolsFramework PrefabUndoInstance* command = aznew PrefabUndoInstance("Entity/Instance duplication"); command->SetParent(undoBatch.GetUndoBatch()); command->Capture(instanceDomBefore, instanceDomAfter, commonOwningInstance->get().GetTemplateId()); - command->Redo(); + command->RedoBatched(); DuplicateNestedInstancesInInstance(commonOwningInstance->get(), instances, instanceDomAfter, duplicatedEntityAndInstanceIds, newInstanceAliasToOldInstanceMap); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp index 29bad78b1c..0ecde973c2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp @@ -146,9 +146,9 @@ namespace AzToolsFramework } } - void PrefabSystemComponent::PropagateTemplateChanges(TemplateId templateId, InstanceOptionalReference instanceToExclude) + void PrefabSystemComponent::PropagateTemplateChanges(TemplateId templateId, bool immediate, InstanceOptionalReference instanceToExclude) { - UpdatePrefabInstances(templateId, instanceToExclude); + UpdatePrefabInstances(templateId, immediate, instanceToExclude); auto templateIdToLinkIdsIterator = m_templateToLinkIdsMap.find(templateId); if (templateIdToLinkIdsIterator != m_templateToLinkIdsMap.end()) @@ -177,9 +177,9 @@ namespace AzToolsFramework } } - void PrefabSystemComponent::UpdatePrefabInstances(TemplateId templateId, InstanceOptionalReference instanceToExclude) + void PrefabSystemComponent::UpdatePrefabInstances(TemplateId templateId, bool immediate, InstanceOptionalReference instanceToExclude) { - m_instanceUpdateExecutor.AddTemplateInstancesToQueue(templateId, instanceToExclude); + m_instanceUpdateExecutor.AddTemplateInstancesToQueue(templateId, immediate, instanceToExclude); } void PrefabSystemComponent::UpdateLinkedInstances(AZStd::queue& linkIdsQueue) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h index 19c7aeb8a9..f640eb2f1b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h @@ -230,14 +230,17 @@ namespace AzToolsFramework */ void UpdatePrefabTemplate(TemplateId templateId, const PrefabDom& updatedDom) override; - void PropagateTemplateChanges(TemplateId templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) override; + void PropagateTemplateChanges(TemplateId templateId, bool immediate = false, InstanceOptionalReference instanceToExclude = AZStd::nullopt) override; /** * Updates all Instances owned by a Template. * * @param templateId The id of the Template owning Instances to update. + * @param immediate An optional flag whether to apply the patch immediately (needed for Undo/Redos) or wait until next system tick. + * @param instanceToExclude An optional reference to an instance of the template being updated that should not be refreshes as part of propagation. + * Defaults to nullopt, which means that all instances will be refreshed. */ - void UpdatePrefabInstances(TemplateId templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt); + void UpdatePrefabInstances(TemplateId templateId, bool immediate = false, InstanceOptionalReference instanceToExclude = AZStd::nullopt); private: AZ_DISABLE_COPY_MOVE(PrefabSystemComponent); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h index 3baaf9ae12..54ca951841 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h @@ -67,7 +67,7 @@ namespace AzToolsFramework virtual PrefabDom& FindTemplateDom(TemplateId templateId) = 0; virtual void UpdatePrefabTemplate(TemplateId templateId, const PrefabDom& updatedDom) = 0; - virtual void PropagateTemplateChanges(TemplateId templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) = 0; + virtual void PropagateTemplateChanges(TemplateId templateId, bool immediate = false, InstanceOptionalReference instanceToExclude = AZStd::nullopt) = 0; virtual AZStd::unique_ptr InstantiatePrefab( AZ::IO::PathView filePath, InstanceOptionalReference parent = AZStd::nullopt) = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp index 385e9b149b..b298304e3b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp @@ -43,10 +43,15 @@ namespace AzToolsFramework void PrefabUndoInstance::Undo() { - m_instanceToTemplateInterface->PatchTemplate(m_undoPatch, m_templateId); + m_instanceToTemplateInterface->PatchTemplate(m_undoPatch, m_templateId, true); } void PrefabUndoInstance::Redo() + { + m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId, true); + } + + void PrefabUndoInstance::RedoBatched() { m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId); } @@ -91,7 +96,7 @@ namespace AzToolsFramework void PrefabUndoEntityUpdate::Undo() { [[maybe_unused]] bool isPatchApplicationSuccessful = - m_instanceToTemplateInterface->PatchTemplate(m_undoPatch, m_templateId); + m_instanceToTemplateInterface->PatchTemplate(m_undoPatch, m_templateId, true); AZ_Error( "Prefab", isPatchApplicationSuccessful, @@ -102,7 +107,7 @@ namespace AzToolsFramework void PrefabUndoEntityUpdate::Redo() { [[maybe_unused]] bool isPatchApplicationSuccessful = - m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId); + m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId, true); AZ_Error( "Prefab", isPatchApplicationSuccessful, @@ -113,7 +118,7 @@ namespace AzToolsFramework void PrefabUndoEntityUpdate::Redo(InstanceOptionalReference instanceToExclude) { [[maybe_unused]] bool isPatchApplicationSuccessful = - m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId, instanceToExclude); + m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId, false, instanceToExclude); AZ_Error( "Prefab", isPatchApplicationSuccessful, @@ -329,7 +334,7 @@ namespace AzToolsFramework //propagate the link changes link->get().UpdateTarget(); - m_prefabSystemComponentInterface->PropagateTemplateChanges(link->get().GetTargetTemplateId(), instanceToExclude); + m_prefabSystemComponentInterface->PropagateTemplateChanges(link->get().GetTargetTemplateId(), false, instanceToExclude); //mark as dirty m_prefabSystemComponentInterface->SetTemplateDirtyFlag(link->get().GetTargetTemplateId(), true); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h index 0af94f86cc..8669024df7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h @@ -53,6 +53,7 @@ namespace AzToolsFramework void Undo() override; void Redo() override; + void RedoBatched(); }; //! handles entity updates, such as when the values on an entity change diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoHelpers.cpp index 9c44fc7ffd..9803b55324 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoHelpers.cpp @@ -26,7 +26,7 @@ namespace AzToolsFramework PrefabUndoInstance* state = aznew Prefab::PrefabUndoInstance(undoMessage); state->Capture(instanceDomBeforeUpdate, instanceDomAfterUpdate, instance.GetTemplateId()); state->SetParent(undoBatch); - state->Redo(); + state->RedoBatched(); } LinkId CreateLink( From f3e6adce7fcff851e3d2a53d5590e4104f4daa16 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 1 Oct 2021 13:52:52 -0700 Subject: [PATCH 50/50] LYN-6882 release builds are executing code in asserts (#4305) * adding Windows/release to PR-validation builds Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * changing trace back to expand to nothing for release Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * typo Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * more fixes Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * fixing some more unused variable cases Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * renaming file in ScriptCanvas that causes a msbuild warning Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * reverting a previous change Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Debug/Trace.h | 20 +++++++++---------- .../AssetBrowser/Views/EntryDelegate.cpp | 2 +- .../Prefab/PrefabSystemComponent.cpp | 5 +++++ .../UI/Prefab/PrefabIntegrationManager.cpp | 2 +- Code/LauncherUnified/Launcher.cpp | 2 ++ .../native/utilities/assetUtils.cpp | 3 +++ .../Factory/TestImpactTestRunSuiteFactory.cpp | 8 ++++++-- .../Code/Tests/ImageProcessing_Test.cpp | 3 ++- .../Code/Source/Editor/ShaderAssetBuilder.cpp | 6 +++--- .../RHI/Code/Source/RHI/FrameScheduler.cpp | 2 +- .../Model/ModelAssetBuilderComponent.cpp | 2 ++ .../RPI.Reflect/Material/MaterialFunctor.cpp | 4 +++- Gems/Atom/Utils/Code/Source/PngFile.cpp | 4 ++-- .../BenchmarkAssetBuilderWorker.cpp | 2 ++ .../ScriptEventsNodePaletteTreeItemTypes.cpp | 2 ++ .../ScriptEvents/ScriptEventDefinition.h | 2 +- ...riptEventMethod.h => ScriptEventsMethod.h} | 0 ...EventMethod.cpp => ScriptEventsMethod.cpp} | 2 +- .../Code/Tests/ScriptEventsTestFixture.h | 2 +- .../Code/scriptevents_common_files.cmake | 4 ++-- .../Rendering/Atom/TangentSpaceHelper.cpp | 2 ++ cmake/Projects.cmake | 6 +++++- .../build/Platform/Windows/build_config.json | 1 + 23 files changed, 58 insertions(+), 28 deletions(-) rename Gems/ScriptEvents/Code/Include/ScriptEvents/{ScriptEventMethod.h => ScriptEventsMethod.h} (100%) rename Gems/ScriptEvents/Code/Source/{ScriptEventMethod.cpp => ScriptEventsMethod.cpp} (99%) diff --git a/Code/Framework/AzCore/AzCore/Debug/Trace.h b/Code/Framework/AzCore/AzCore/Debug/Trace.h index a1334d334e..507ba48e53 100644 --- a/Code/Framework/AzCore/AzCore/Debug/Trace.h +++ b/Code/Framework/AzCore/AzCore/Debug/Trace.h @@ -262,17 +262,17 @@ namespace AZ #else // !AZ_ENABLE_TRACING - #define AZ_Assert(...) AZ_UNUSED(__VA_ARGS__); - #define AZ_Error(...) AZ_UNUSED(__VA_ARGS__); - #define AZ_ErrorOnce(...) AZ_UNUSED(__VA_ARGS__); - #define AZ_Warning(...) AZ_UNUSED(__VA_ARGS__); - #define AZ_WarningOnce(...) AZ_UNUSED(__VA_ARGS__); - #define AZ_TracePrintf(...) AZ_UNUSED(__VA_ARGS__); - #define AZ_TracePrintfOnce(...) AZ_UNUSED(__VA_ARGS__); + #define AZ_Assert(...) + #define AZ_Error(...) + #define AZ_ErrorOnce(...) + #define AZ_Warning(...) + #define AZ_WarningOnce(...) + #define AZ_TracePrintf(...) + #define AZ_TracePrintfOnce(...) - #define AZ_Verify(...) AZ_UNUSED(__VA_ARGS__); - #define AZ_VerifyError(...) AZ_UNUSED(__VA_ARGS__); - #define AZ_VerifyWarning(...) AZ_UNUSED(__VA_ARGS__); + #define AZ_Verify(expression, ...) AZ_UNUSED(expression) + #define AZ_VerifyError(window, expression, ...) AZ_UNUSED(expression) + #define AZ_VerifyWarning(window, expression, ...) AZ_UNUSED(expression) #endif // AZ_ENABLE_TRACING diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp index 755c59b55b..b463381638 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp @@ -290,7 +290,7 @@ namespace AzToolsFramework absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathOneChild; break; } - bool pixmapLoadedSuccess = pixmap.load(absoluteIconPath.c_str()); + [[maybe_unused]] bool pixmapLoadedSuccess = pixmap.load(absoluteIconPath.c_str()); AZ_Assert(pixmapLoadedSuccess, "Error loading Branch Icons in SearchEntryDelegate"); m_branchIcons[static_cast(branchType)] = pixmap; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp index 0ecde973c2..4f8f575a7b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp @@ -579,10 +579,13 @@ namespace AzToolsFramework Template& targetTemplate = targetTemplateReference->get(); +#if defined(AZ_ENABLE_TRACING) Template& sourceTemplate = sourceTemplateReference->get(); AZStd::string_view instanceName(instanceIterator->name.GetString(), instanceIterator->name.GetStringLength()); + const AZStd::string& targetTemplateFilePath = targetTemplate.GetFilePath().Native(); const AZStd::string& sourceTemplateFilePath = sourceTemplate.GetFilePath().Native(); +#endif LinkId newLinkId = CreateUniqueLinkId(); Link newLink(newLinkId); @@ -911,8 +914,10 @@ namespace AzToolsFramework return false; } +#if defined(AZ_ENABLE_TRACING) Template& sourceTemplate = sourceTemplateReference->get(); Template& targetTemplate = targetTemplateReference->get(); +#endif AZStd::string_view instanceName(instanceIterator->name.GetString(), instanceIterator->name.GetStringLength()); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index 9b7f2fff10..34152f8287 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -1160,7 +1160,7 @@ namespace AzToolsFramework AZStd::string unsavedPrefabFileName = unsavedPrefabFileLabel->property("FilePath").toString().toUtf8().data(); AzToolsFramework::Prefab::TemplateId unsavedPrefabTemplateId = s_prefabSystemComponentInterface->GetTemplateIdFromFilePath(unsavedPrefabFileName.data()); - bool isTemplateSavedSuccessfully = s_prefabLoaderInterface->SaveTemplate(unsavedPrefabTemplateId); + [[maybe_unused]] bool isTemplateSavedSuccessfully = s_prefabLoaderInterface->SaveTemplate(unsavedPrefabTemplateId); AZ_Error("Prefab", isTemplateSavedSuccessfully, "Prefab '%s' could not be saved successfully.", unsavedPrefabFileName.c_str()); } } diff --git a/Code/LauncherUnified/Launcher.cpp b/Code/LauncherUnified/Launcher.cpp index 27aab074ef..0ef9cdfc3b 100644 --- a/Code/LauncherUnified/Launcher.cpp +++ b/Code/LauncherUnified/Launcher.cpp @@ -627,8 +627,10 @@ namespace O3DELauncher AZ_TracePrintf("Launcher", "Application is configured for VFS"); AZ_TracePrintf("Launcher", "Log and cache files will be written to the Cache directory on your host PC"); +#if defined(AZ_ENABLE_TRACING) constexpr const char* message = "If your game does not run, check any of the following:\n" "\t- Verify the remote_ip address is correct in bootstrap.cfg"; +#endif if (mainInfo.m_additionalVfsResolution) { AZ_TracePrintf("Launcher", "%s\n%s", message, mainInfo.m_additionalVfsResolution) diff --git a/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp b/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp index c0e907f2d5..cacd6c4cc9 100644 --- a/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp @@ -164,7 +164,10 @@ namespace AssetUtilsInternal AZ::SettingsRegistryMergeUtils::DumperSettings apDumperSettings; apDumperSettings.m_prettifyOutput = true; + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning apDumperSettings.m_includeFilter = [&AssetProcessorUserSettingsRootKey](AZStd::string_view path) + AZ_POP_DISABLE_WARNING { // The AssetUtils only updates the following keys in the registry // Dump them all out to the setreg file diff --git a/Code/Tools/TestImpactFramework/Runtime/Code/Source/Artifact/Factory/TestImpactTestRunSuiteFactory.cpp b/Code/Tools/TestImpactFramework/Runtime/Code/Source/Artifact/Factory/TestImpactTestRunSuiteFactory.cpp index b7a44d43ea..f39cfaaf10 100644 --- a/Code/Tools/TestImpactFramework/Runtime/Code/Source/Artifact/Factory/TestImpactTestRunSuiteFactory.cpp +++ b/Code/Tools/TestImpactFramework/Runtime/Code/Source/Artifact/Factory/TestImpactTestRunSuiteFactory.cpp @@ -64,9 +64,11 @@ namespace TestImpact return !name.starts_with("DISABLED_") && name.find("/DISABLED_") == AZStd::string::npos; }; + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr + // in the capture. Newer versions issue unused warning const auto getDuration = [Keys](const AZ::rapidxml::xml_node<>* node) + AZ_POP_DISABLE_WARNING { - AZ_UNUSED(Keys); const AZStd::string duration = node->first_attribute(Keys[DurationKey])->value(); return AZStd::chrono::milliseconds(static_cast(AZStd::stof(duration) * 1000.f)); }; @@ -79,9 +81,11 @@ namespace TestImpact for (auto testcase_node = testsuite_node->first_node(Keys[TestCaseKey]); testcase_node; testcase_node = testcase_node->next_sibling()) { + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the capture. + // Newer versions issue unused warning const auto getStatus = [Keys](const AZ::rapidxml::xml_node<>* node) + AZ_POP_DISABLE_WARNING { - AZ_UNUSED(Keys); const AZStd::string status = node->first_attribute(Keys[StatusKey])->value(); if (status == Keys[RunKey]) { diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp index c4240306c4..c72e1dc309 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp @@ -860,8 +860,9 @@ namespace UnitTest { continue; } - +#if defined(AZ_ENABLE_TRACING) auto formatInfo = CPixelFormats::GetInstance().GetPixelFormatInfo(pixelFormat); +#endif ColorSpace sourceColorSpace = srcImage->HasImageFlags(EIF_SRGBRead) ? ColorSpace::sRGB : ColorSpace::linear; ICompressorPtr compressor = ICompressor::FindCompressor(pixelFormat, sourceColorSpace, true); diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp index 2babba1ecc..3bc63b89a0 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp @@ -228,9 +228,9 @@ namespace AZ response.m_createJobOutputs.push_back(jobDescriptor); } // for all request.m_enabledPlatforms - const AZStd::sys_time_t createJobsEndStamp = AZStd::GetTimeNowMicroSecond(); - const u64 createJobDurationMicros = createJobsEndStamp - shaderAssetBuildTimestamp; - AZ_TracePrintf(ShaderAssetBuilderName, "CreateJobs for %s took %llu microseconds", fullPath.c_str(), createJobDurationMicros ); + AZ_TracePrintf( + ShaderAssetBuilderName, "CreateJobs for %s took %llu microseconds", fullPath.c_str(), + AZStd::GetTimeNowMicroSecond() - shaderAssetBuildTimestamp); response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success; } diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp index 3363675d0e..0d3ac8216b 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp @@ -370,7 +370,7 @@ namespace AZ //It is possible for certain back ends to run out of SRG memory (due to fragmentation) in which case //we try to compact and re-compile SRGs. - RHI::ResultCode resultCode = m_device->CompactSRGMemory(); + [[maybe_unused]] RHI::ResultCode resultCode = m_device->CompactSRGMemory(); AZ_Assert(resultCode == RHI::ResultCode::Success, "SRG compaction failed and this can lead to a gpu crash."); } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp index 1da16b44b6..9fc99e3ea4 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp @@ -1078,7 +1078,9 @@ namespace AZ template void ModelAssetBuilderComponent::ValidateStreamSize([[maybe_unused]] size_t expectedVertexCount, [[maybe_unused]] const AZStd::vector& bufferData, [[maybe_unused]] AZ::RHI::Format format, [[maybe_unused]] const char* streamName) const { +#if defined(AZ_ENABLE_TRACING) size_t actualVertexCount = (bufferData.size() * sizeof(T)) / RHI::GetFormatSize(format); +#endif AZ_Error(s_builderName, expectedVertexCount == actualVertexCount, "VertexStream '%s' does not match the expected vertex count. This typically means multiple sub-meshes have mis-matched vertex stream layouts (such as one having more uv sets than the other) but are assigned the same material in the dcc tool so they were merged.", streamName); } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialFunctor.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialFunctor.cpp index 0f70d0af35..52b6349ca0 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialFunctor.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialFunctor.cpp @@ -417,14 +417,16 @@ namespace AZ template const Color& MaterialFunctor::EditorContext::GetMaterialPropertyValue (const MaterialPropertyIndex& index) const; template const Data::Instance& MaterialFunctor::EditorContext::GetMaterialPropertyValue> (const MaterialPropertyIndex& index) const; - void CheckPropertyAccess(const MaterialPropertyIndex& index, const MaterialPropertyFlags& materialPropertyDependencies, [[maybe_unused]] const MaterialPropertiesLayout& materialPropertiesLayout) + void CheckPropertyAccess([[maybe_unused]] const MaterialPropertyIndex& index, [[maybe_unused]] const MaterialPropertyFlags& materialPropertyDependencies, [[maybe_unused]] const MaterialPropertiesLayout& materialPropertiesLayout) { +#if defined(AZ_ENABLE_TRACING) if (!materialPropertyDependencies.test(index.GetIndex())) { const MaterialPropertyDescriptor* propertyDescriptor = materialPropertiesLayout.GetPropertyDescriptor(index); AZ_Error("MaterialFunctor", false, "Material functor accessing an unregistered material property '%s'.", propertyDescriptor ? propertyDescriptor->GetName().GetCStr() : ""); } +#endif } const MaterialPropertyValue& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue(const MaterialPropertyIndex& index) const diff --git a/Gems/Atom/Utils/Code/Source/PngFile.cpp b/Gems/Atom/Utils/Code/Source/PngFile.cpp index 09a5d950e5..28f5374d88 100644 --- a/Gems/Atom/Utils/Code/Source/PngFile.cpp +++ b/Gems/Atom/Utils/Code/Source/PngFile.cpp @@ -21,7 +21,7 @@ namespace AZ (*errorHandler)(error_msg); } - void PngImage_user_warning_fn(png_structp /*png_ptr*/, png_const_charp warning_msg) + void PngImage_user_warning_fn(png_structp /*png_ptr*/, [[maybe_unused]] png_const_charp warning_msg) { AZ_Warning("PngFile", false, "%s", warning_msg); } @@ -301,7 +301,7 @@ AZ_POP_DISABLE_WARNING return true; } - void PngFile::DefaultErrorHandler(const char* message) + void PngFile::DefaultErrorHandler([[maybe_unused]] const char* message) { AZ_Error("PngFile", false, "%s", message); } diff --git a/Gems/LmbrCentral/Code/Source/Builders/BenchmarkAssetBuilder/BenchmarkAssetBuilderWorker.cpp b/Gems/LmbrCentral/Code/Source/Builders/BenchmarkAssetBuilder/BenchmarkAssetBuilderWorker.cpp index 22be22265a..da7181ae04 100644 --- a/Gems/LmbrCentral/Code/Source/Builders/BenchmarkAssetBuilder/BenchmarkAssetBuilderWorker.cpp +++ b/Gems/LmbrCentral/Code/Source/Builders/BenchmarkAssetBuilder/BenchmarkAssetBuilderWorker.cpp @@ -253,10 +253,12 @@ namespace BenchmarkAssetBuilder // and 2 bytes of storage for text-based formats. // This is just an approximate total size because there's a bit of additional overhead // for asset headers and the other fields in the generated asset. +#if defined(AZ_ENABLE_TRACING) uint64_t approximateTotalStorageBytes = (settingsPtr->m_assetStorageType == AZ::DataStream::StreamType::ST_BINARY) ? UINT64_C(1) * totalGeneratedBytes : UINT64_C(2) * totalGeneratedBytes; +#endif AZ_TracePrintf(AssetBuilderSDK::InfoWindow, "Benchmark asset generation will generate %" PRIu64 " assets " diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/ScriptEventsNodePaletteTreeItemTypes.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/ScriptEventsNodePaletteTreeItemTypes.cpp index 704f67e034..da0e9c6045 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/ScriptEventsNodePaletteTreeItemTypes.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/ScriptEventsNodePaletteTreeItemTypes.cpp @@ -154,7 +154,9 @@ namespace ScriptCanvasEditor const ScriptEvents::ScriptEvent& definition = data->m_definition; +#if defined(AZ_ENABLE_TRACING) bool recategorize = previousDefinition ? definition.GetCategory().compare(previousDefinition->GetCategory()) != 0 : false; +#endif AZ_Warning("ScriptCanvas", !recategorize, "Unable to recategorize ScriptEvents events while open. Please close and re-open the Script Canvas Editor to see the new categorization"); if (definition.GetName().empty()) diff --git a/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventDefinition.h b/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventDefinition.h index bc8112802b..a56e9b422b 100644 --- a/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventDefinition.h +++ b/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventDefinition.h @@ -11,7 +11,7 @@ #include #include -#include +#include #include namespace ScriptEvents diff --git a/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventMethod.h b/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventsMethod.h similarity index 100% rename from Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventMethod.h rename to Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventsMethod.h diff --git a/Gems/ScriptEvents/Code/Source/ScriptEventMethod.cpp b/Gems/ScriptEvents/Code/Source/ScriptEventsMethod.cpp similarity index 99% rename from Gems/ScriptEvents/Code/Source/ScriptEventMethod.cpp rename to Gems/ScriptEvents/Code/Source/ScriptEventsMethod.cpp index 5b7bb590af..579c51a782 100644 --- a/Gems/ScriptEvents/Code/Source/ScriptEventMethod.cpp +++ b/Gems/ScriptEvents/Code/Source/ScriptEventsMethod.cpp @@ -6,7 +6,7 @@ * */ -#include "ScriptEvents/ScriptEventMethod.h" +#include "ScriptEvents/ScriptEventsMethod.h" #include #include diff --git a/Gems/ScriptEvents/Code/Tests/ScriptEventsTestFixture.h b/Gems/ScriptEvents/Code/Tests/ScriptEventsTestFixture.h index 78c7308dde..53d4fd58b9 100644 --- a/Gems/ScriptEvents/Code/Tests/ScriptEventsTestFixture.h +++ b/Gems/ScriptEvents/Code/Tests/ScriptEventsTestFixture.h @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include "ScriptEventTestUtilities.h" diff --git a/Gems/ScriptEvents/Code/scriptevents_common_files.cmake b/Gems/ScriptEvents/Code/scriptevents_common_files.cmake index 5938050f5d..a7ecd9e049 100644 --- a/Gems/ScriptEvents/Code/scriptevents_common_files.cmake +++ b/Gems/ScriptEvents/Code/scriptevents_common_files.cmake @@ -10,7 +10,7 @@ set(FILES Source/ScriptEventsSystemComponent.h Source/ScriptEventsSystemComponent.cpp Source/ScriptEventParameter.cpp - Source/ScriptEventMethod.cpp + Source/ScriptEventsMethod.cpp Source/ScriptEventsAssetRef.cpp Include/ScriptEvents/ScriptEventsGem.h Include/ScriptEvents/ScriptEventsAsset.h @@ -23,7 +23,7 @@ set(FILES Include/ScriptEvents/ScriptEventDefinition.h Include/ScriptEvents/ScriptEventDefinition.cpp Include/ScriptEvents/ScriptEvent.h - Include/ScriptEvents/ScriptEventMethod.h + Include/ScriptEvents/ScriptEventsMethod.h Include/ScriptEvents/ScriptEvent.cpp Include/ScriptEvents/ScriptEventParameter.h Include/ScriptEvents/ScriptEventSystem.h diff --git a/Gems/WhiteBox/Code/Source/Rendering/Atom/TangentSpaceHelper.cpp b/Gems/WhiteBox/Code/Source/Rendering/Atom/TangentSpaceHelper.cpp index a43b48d3b9..913778cc44 100644 --- a/Gems/WhiteBox/Code/Source/Rendering/Atom/TangentSpaceHelper.cpp +++ b/Gems/WhiteBox/Code/Source/Rendering/Atom/TangentSpaceHelper.cpp @@ -73,7 +73,9 @@ namespace WhiteBox for (AZ::u32 i = 0; i < triangleCount; ++i) { +#if defined(AZ_ENABLE_TRACING) const auto& trianglePositions = trianglesPositions[i]; +#endif const auto& triangleUVs = trianglesUVs[i]; const auto& triangleEdges = trianglesEdges[i]; diff --git a/cmake/Projects.cmake b/cmake/Projects.cmake index b21704ee85..6109229e72 100644 --- a/cmake/Projects.cmake +++ b/cmake/Projects.cmake @@ -10,7 +10,11 @@ include_guard() -set(LY_PROJECTS "" CACHE STRING "List of projects to enable, this can be a relative path to the engine root or an absolute path") +# Passing ${LY_PROJECTS} as the default since in project-centric LY_PROJECTS is defined by the project and +# we want to pick up that one as the value of the variable. +# Ideally this cache variable would be defined before the project sets LY_PROJECTS, but that would mean +# it would have to be defined in each project. +set(LY_PROJECTS "${LY_PROJECTS}" CACHE STRING "List of projects to enable, this can be a relative path to the engine root or an absolute path") #! ly_add_target_dependencies: adds module load dependencies for this target. # diff --git a/scripts/build/Platform/Windows/build_config.json b/scripts/build/Platform/Windows/build_config.json index e33025a4d9..c607c3d821 100644 --- a/scripts/build/Platform/Windows/build_config.json +++ b/scripts/build/Platform/Windows/build_config.json @@ -306,6 +306,7 @@ }, "release_vs2019": { "TAGS": [ + "default", "nightly-incremental", "nightly-clean", "weekly-build-metrics"