diff --git a/Assets/Editor/Translation/scriptcanvas_en_us.ts b/Assets/Editor/Translation/scriptcanvas_en_us.ts index 937f6a4d96..7b8361c879 100644 --- a/Assets/Editor/Translation/scriptcanvas_en_us.ts +++ b/Assets/Editor/Translation/scriptcanvas_en_us.ts @@ -8098,7 +8098,7 @@ COLOR_FROMVALUES_PARAM0_TOOLTIP - The Red value of hte Color [0, 255] + The Red value of the Color [0.0-1.0] COLOR_FROMVALUES_PARAM1_NAME @@ -8107,7 +8107,7 @@ COLOR_FROMVALUES_PARAM1_TOOLTIP - The Green value of the Color [0, 255] + The Green value of the Color [0.0-1.0] COLOR_FROMVALUES_PARAM2_NAME @@ -8116,7 +8116,7 @@ COLOR_FROMVALUES_PARAM2_TOOLTIP - The Blue value of the Color [0, 255] + The Blue value of the Color [0.0-1.0] COLOR_FROMVALUES_PARAM3_NAME @@ -8125,7 +8125,7 @@ COLOR_FROMVALUES_PARAM3_TOOLTIP - The Alpha value of the Color [0, 255] + The Alpha value of the Color [0.0-1.0] diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/CMakeLists.txt index 4a26500ee2..52682e70bb 100644 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/CMakeLists.txt @@ -17,5 +17,14 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) AZ::AssetProcessorBatch AZ::AssetProcessor ) + + ly_add_pytest( + NAME AssetPipelineTests.Fbx_Tests + PATH ${CMAKE_CURRENT_LIST_DIR}/fbx_test/fbx_test.py + TEST_SUITE sandbox + RUNTIME_DEPENDENCIES + AZ::AssetProcessorBatch + AZ::AssetProcessor + ) endif() diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py index 2b90f53fc3..5cb61da68e 100755 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py @@ -34,11 +34,13 @@ logger = logging.getLogger(__name__) targetProjects = ["AutomatedTesting"] @pytest.fixture +@pytest.mark.SUITE_sandbox def local_resources(request, workspace, ap_setup_fixture): ap_setup_fixture["tests_dir"] = os.path.dirname(os.path.realpath(__file__)) @dataclass +@pytest.mark.SUITE_sandbox class BlackboxAssetTest: test_name: str asset_folder: str @@ -338,9 +340,11 @@ blackbox_fbx_special_tests = [ @pytest.mark.usefixtures("local_resources") @pytest.mark.parametrize("project", targetProjects) @pytest.mark.assetpipeline +@pytest.mark.SUITE_sandbox class TestsFBX_AllPlatforms(object): @pytest.mark.BAT + @pytest.mark.SUITE_sandbox @pytest.mark.parametrize("blackbox_param", blackbox_fbx_tests) def test_FBXBlackboxTest_SourceFiles_Processed_ResultInExpectedProducts(self, workspace, ap_setup_fixture, asset_processor, project, @@ -359,6 +363,7 @@ class TestsFBX_AllPlatforms(object): asset_processor, project, blackbox_param) @pytest.mark.BAT + @pytest.mark.SUITE_sandbox @pytest.mark.parametrize("blackbox_param", blackbox_fbx_special_tests) def test_FBXBlackboxTest_AssetInfoModified_AssetReprocessed_ResultInExpectedProducts(self, workspace, ap_setup_fixture, diff --git a/Code/Framework/AzCore/AzCore/Component/Entity.cpp b/Code/Framework/AzCore/AzCore/Component/Entity.cpp index 00c1895261..2e92873238 100644 --- a/Code/Framework/AzCore/AzCore/Component/Entity.cpp +++ b/Code/Framework/AzCore/AzCore/Component/Entity.cpp @@ -207,12 +207,6 @@ namespace AZ ActivateComponent(**it); } - // Cache the transform interface to the transform interface - // Generally this pattern is not recommended unless for component event buses - // As we have a guarantee (by design) that components can't change during active state) - // Even though technically they can connect disconnect from the bus. - m_transform = TransformBus::FindFirstHandler(m_id); - SetState(State::Active); EBUS_EVENT_ID(m_id, EntityBus, OnEntityActivated, m_id); @@ -1320,6 +1314,19 @@ namespace AZ return *processSignature; } + AZ::TransformInterface* Entity::GetTransform() const + { + // Lazy evaluation of the cached entity transform. + if(!m_transform) + { + // Generally this pattern is not recommended unless for component event buses + // As we have a guarantee (by design) that components can't change during active state) + // Even though technically they can connect disconnect from the bus. + m_transform = TransformBus::FindFirstHandler(m_id); + } + return m_transform; + } + //========================================================================= // MakeId // Ids must be unique across a project at authoring time. Runtime doesn't matter diff --git a/Code/Framework/AzCore/AzCore/Component/Entity.h b/Code/Framework/AzCore/AzCore/Component/Entity.h index 7ec63a56ac..356533f268 100644 --- a/Code/Framework/AzCore/AzCore/Component/Entity.h +++ b/Code/Framework/AzCore/AzCore/Component/Entity.h @@ -354,10 +354,9 @@ namespace AZ //! @return The Process Signature of the local machine. static AZ::u32 GetProcessSignature(); - /// @cond EXCLUDE_DOCS - //! @deprecated Use the TransformBus to communicate with the TransformInterface. - inline TransformInterface* GetTransform() const { return m_transform; } - /// @endcond + //! Gets the TransformInterface for the entity. + //! @return The TransformInterface for the entity. + TransformInterface* GetTransform() const; //! Sorts an entity's components based on the dependencies between components. //! If all dependencies are met, the required services can be activated @@ -406,7 +405,7 @@ namespace AZ //! A cached pointer to the transform interface. //! We recommend using AZ::TransformBus and caching locally instead of accessing //! the transform interface directly through this pointer. - TransformInterface* m_transform; + mutable TransformInterface* m_transform; //! A user-friendly name for the entity. This makes error messages easier to read. AZStd::string m_name; diff --git a/Code/Framework/AzCore/AzCore/IO/FileReader.cpp b/Code/Framework/AzCore/AzCore/IO/FileReader.cpp new file mode 100644 index 0000000000..94118cdfe4 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/IO/FileReader.cpp @@ -0,0 +1,200 @@ +/* + * 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 AZ::IO +{ + FileReader::FileReader() = default; + + FileReader::FileReader(AZ::IO::FileIOBase* fileIoBase, const char* filePath) + { + Open(fileIoBase, filePath); + } + + FileReader::~FileReader() + { + Close(); + } + + FileReader::FileReader(FileReader&& other) + { + AZStd::swap(m_file, other.m_file); + AZStd::swap(m_fileIoBase, other.m_fileIoBase); + } + + FileReader& FileReader::operator=(FileReader&& other) + { + // Close the current file and take over other file + Close(); + m_file = AZStd::move(other.m_file); + m_fileIoBase = AZStd::move(other.m_fileIoBase); + other.m_file = AZStd::monostate{}; + other.m_fileIoBase = {}; + + return *this; + } + + bool FileReader::Open(AZ::IO::FileIOBase* fileIoBase, const char* filePath) + { + // Close file if the FileReader has an instance open + Close(); + + if (fileIoBase != nullptr) + { + AZ::IO::HandleType fileHandle; + if (fileIoBase->Open(filePath, IO::OpenMode::ModeRead, fileHandle)) + { + m_file = fileHandle; + m_fileIoBase = fileIoBase; + return true; + } + } + else + { + AZ::IO::SystemFile file; + if (file.Open(filePath, IO::SystemFile::OpenMode::SF_OPEN_READ_ONLY)) + { + m_file = AZStd::move(file); + return true; + } + } + + return false; + } + + bool FileReader::IsOpen() const + { + if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr) + { + return *fileHandle != AZ::IO::InvalidHandle; + } + else if (auto systemFile = AZStd::get_if(&m_file); systemFile != nullptr) + { + return systemFile->IsOpen(); + } + + return false; + } + + void FileReader::Close() + { + if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr) + { + if (AZ::IO::FileIOBase* fileIo = m_fileIoBase; fileIo != nullptr) + { + fileIo->Close(*fileHandle); + } + } + + m_file = AZStd::monostate{}; + m_fileIoBase = {}; + } + + auto FileReader::Length() const -> SizeType + { + if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr) + { + if (SizeType fileSize{}; m_fileIoBase->Size(*fileHandle, fileSize)) + { + return fileSize; + } + } + else if (auto systemFile = AZStd::get_if(&m_file); systemFile != nullptr) + { + return systemFile->Length(); + } + + return 0; + } + + auto FileReader::Read(SizeType byteSize, void* buffer) -> SizeType + { + if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr) + { + if (SizeType bytesRead{}; m_fileIoBase->Read(*fileHandle, buffer, byteSize, false, &bytesRead)) + { + return bytesRead; + } + } + else if (auto systemFile = AZStd::get_if(&m_file); systemFile != nullptr) + { + return systemFile->Read(byteSize, buffer); + } + + return 0; + } + + auto FileReader::Tell() const -> SizeType + { + if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr) + { + if (SizeType fileOffset{}; m_fileIoBase->Tell(*fileHandle, fileOffset)) + { + return fileOffset; + } + } + else if (auto systemFile = AZStd::get_if(&m_file); systemFile != nullptr) + { + return systemFile->Tell(); + } + + return 0; + } + + bool FileReader::Seek(AZ::s64 offset, SeekType type) + { + if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr) + { + return m_fileIoBase->Seek(*fileHandle, offset, type); + } + else if (auto systemFile = AZStd::get_if(&m_file); systemFile != nullptr) + { + systemFile->Seek(offset, static_cast(type)); + return true; + } + + return false; + } + + bool FileReader::Eof() const + { + if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr) + { + return m_fileIoBase->Eof(*fileHandle); + } + else if (auto systemFile = AZStd::get_if(&m_file); systemFile != nullptr) + { + return systemFile->Eof(); + } + + return false; + } + + bool FileReader::GetFilePath(AZ::IO::FixedMaxPath& filePath) const + { + if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr) + { + AZ::IO::FixedMaxPathString& pathStringRef = filePath.Native(); + if (m_fileIoBase->GetFilename(*fileHandle, pathStringRef.data(), pathStringRef.capacity())) + { + pathStringRef.resize_no_construct(AZStd::char_traits::length(pathStringRef.data())); + return true; + } + } + else if (auto systemFile = AZStd::get_if(&m_file); systemFile != nullptr) + { + filePath = systemFile->Name(); + return true; + } + + return false; + } +} diff --git a/Code/Framework/AzCore/AzCore/IO/FileReader.h b/Code/Framework/AzCore/AzCore/IO/FileReader.h new file mode 100644 index 0000000000..4fdb18b2b2 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/IO/FileReader.h @@ -0,0 +1,92 @@ +/* + * 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 AZ::IO +{ + class FileIOBase; + enum class SeekType : AZ::u32; + + //! Structure which encapsulates delegates File Read operations + //! to either the FileIOBase or SystemFile classes based if a FileIOBase* instance has been supplied + //! to the FileSystemReader class + //! the SettingsRegistry option to use FileIO + class FileReader + { + using HandleType = AZ::u32; + using FileHandleType = AZStd::variant; + public: + using SizeType = AZ::u64; + + //! Creates FileReader instance in the default state with no file opend + FileReader(); + ~FileReader(); + + //! Creates a new FileReader instance and attempts to open the file at the supplied path + //! Uses the FileIOBase instance if supplied + //! @param fileIOBase pointer to fileIOBase instance + //! @param null-terminated filePath to open + FileReader(AZ::IO::FileIOBase* fileIoBase, const char* filePath); + + //! Takes ownership of the supplied FileReader handle + FileReader(FileReader&& other); + + //! Moves ownership of FileReader handle to this instance + FileReader& operator=(FileReader&& other); + + //! Opens a File using the FileIOBase instance if non-nullptr + //! Otherwise fall back to use SystemFile + //! @param fileIOBase pointer to fileIOBase instance + //! @param null-terminated filePath to open + //! @return true if the File is opened successfully + bool Open(AZ::IO::FileIOBase* fileIoBase, const char* filePath); + + //! Returns true if a file is currently open + //! @return true if the file is open + bool IsOpen() const; + + //! Closes the File + void Close(); + + //! Retrieve the length of the OpenFile + SizeType Length() const; + + //! Attempts to read up to byte size bytes into the supplied buffer + //! @param byteSize - Maximum number of bytes to read + //! @param buffer - Buffer to read bytes into + //! @returns the number of bytes read if the file is open, otherwise 0 + SizeType Read(SizeType byteSize, void* buffer); + + //! Returns the current file offset + //! @returns file offset if the file is open, otherwise 0 + SizeType Tell() const; + + //! Seeks within the open file to the offset supplied + //! @param offset File offset to seek to + //! @param type parameter to indicate the reference point to start the seek from + //! @returns true if the file is open and the seek succeeded + bool Seek(AZ::s64 offset, SeekType type); + + //! Returns true if the file is open and in the EOF state + bool Eof() const; + + //! Store the file path of the open file into the output file path parameter + //! The filePath reference is left unmodified, if the path was not stored + //! @return true if the filePath was stored + bool GetFilePath(AZ::IO::FixedMaxPath& filePath) const; + + private: + + FileHandleType m_file; + AZ::IO::FileIOBase* m_fileIoBase{}; + }; +} diff --git a/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp b/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp index 5bff79b422..651abb89fe 100644 --- a/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp +++ b/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp @@ -160,12 +160,12 @@ void SystemFile::Seek(SeekSizeType offset, SeekMode mode) Platform::Seek(m_handle, this, offset, mode); } -SystemFile::SizeType SystemFile::Tell() +SystemFile::SizeType SystemFile::Tell() const { return Platform::Tell(m_handle, this); } -bool SystemFile::Eof() +bool SystemFile::Eof() const { return Platform::Eof(m_handle, this); } diff --git a/Code/Framework/AzCore/AzCore/IO/SystemFile.h b/Code/Framework/AzCore/AzCore/IO/SystemFile.h index 8a5b2b2521..551ce89ce7 100644 --- a/Code/Framework/AzCore/AzCore/IO/SystemFile.h +++ b/Code/Framework/AzCore/AzCore/IO/SystemFile.h @@ -72,9 +72,9 @@ namespace AZ /// Seek in current file. void Seek(SeekSizeType offset, SeekMode mode); /// Get the cursor position in the current file. - SizeType Tell(); + SizeType Tell() const; /// Is the cursor at the end of the file? - bool Eof(); + bool Eof() const; /// Get the time the file was last modified. AZ::u64 ModificationTime(); /// Read data from a file synchronous. Return number of bytes actually read in the buffer. diff --git a/Code/Framework/AzCore/AzCore/Math/Transform.cpp b/Code/Framework/AzCore/AzCore/Math/Transform.cpp index 5cb09fe9a8..1701820bae 100644 --- a/Code/Framework/AzCore/AzCore/Math/Transform.cpp +++ b/Code/Framework/AzCore/AzCore/Math/Transform.cpp @@ -353,6 +353,7 @@ namespace AZ Method("CreateFromMatrix3x3AndTranslation", &Transform::CreateFromMatrix3x3AndTranslation)-> Method("CreateUniformScale", &Transform::CreateUniformScale)-> Method("CreateTranslation", &Transform::CreateTranslation)-> + Method("CreateLookAt", &Transform::CreateLookAt)-> Method("ConstructFromValuesNumeric", &Internal::ConstructTransformFromValues); } } diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp index 7ef1fa661d..92f546815e 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -1116,118 +1117,6 @@ namespace AZ } } - //! Structure which encapsulates Commands to either the FileIOBase or SystemFile classes based on - //! the SettingsRegistry option to use FileIO - struct SettingsRegistryFileReader - { - using FileHandleType = AZStd::variant; - - SettingsRegistryFileReader() = default; - SettingsRegistryFileReader(bool useFileIo, const char* filePath) - { - Open(useFileIo, filePath); - } - - ~SettingsRegistryFileReader() - { - if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr) - { - if (AZ::IO::FileIOBase* fileIo = AZ::IO::FileIOBase::GetInstance(); fileIo != nullptr) - { - fileIo->Close(*fileHandle); - } - } - } - - bool Open(bool useFileIo, const char* filePath) - { - Close(); - if (AZ::IO::FileIOBase* fileIo = useFileIo ? AZ::IO::FileIOBase::GetInstance() : nullptr; fileIo != nullptr) - { - AZ::IO::HandleType fileHandle; - if (fileIo->Open(filePath, IO::OpenMode::ModeRead, fileHandle)) - { - m_file = fileHandle; - return true; - } - } - else - { - AZ::IO::SystemFile file; - if (file.Open(filePath, IO::SystemFile::OpenMode::SF_OPEN_READ_ONLY)) - { - m_file = AZStd::move(file); - return true; - } - } - - return false; - } - - bool IsOpen() const - { - if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr) - { - return *fileHandle != AZ::IO::InvalidHandle; - } - else if (auto systemFile = AZStd::get_if(&m_file); systemFile != nullptr) - { - return systemFile->IsOpen(); - } - - return false; - } - - void Close() - { - if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr) - { - if (AZ::IO::FileIOBase* fileIo = AZ::IO::FileIOBase::GetInstance(); fileIo != nullptr) - { - fileIo->Close(*fileHandle); - } - } - - m_file = AZStd::monostate{}; - } - - u64 Length() const - { - if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr) - { - if (u64 fileSize{}; AZ::IO::FileIOBase::GetInstance()->Size(*fileHandle, fileSize)) - { - return fileSize; - } - } - else if (auto systemFile = AZStd::get_if(&m_file); systemFile != nullptr) - { - return systemFile->Length(); - } - - return 0; - } - - AZ::IO::SizeType Read(AZ::IO::SizeType byteSize, void* buffer) - { - if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr) - { - if (AZ::u64 bytesRead{}; AZ::IO::FileIOBase::GetInstance()->Read(*fileHandle, buffer, byteSize, false, &bytesRead)) - { - return bytesRead; - } - } - else if (auto systemFile = AZStd::get_if(&m_file); systemFile != nullptr) - { - return systemFile->Read(byteSize, buffer); - } - - return 0; - } - - FileHandleType m_file; - }; - bool SettingsRegistryImpl::MergeSettingsFileInternal(const char* path, Format format, AZStd::string_view rootKey, AZStd::vector& scratchBuffer) { @@ -1236,7 +1125,7 @@ namespace AZ Pointer pointer(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/-"); - SettingsRegistryFileReader fileReader(m_useFileIo, path); + FileReader fileReader(m_useFileIo ? AZ::IO::FileIOBase::GetInstance(): nullptr, path); if (!fileReader.IsOpen()) { AZ_Error("Settings Registry", false, R"(Unable to open registry file "%s".)", path); diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index 5290c9b02a..da7110e36e 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -6,6 +6,8 @@ * */ +#include +#include #include #include #include @@ -388,8 +390,36 @@ namespace AZ::SettingsRegistryMergeUtils const ConfigParserSettings& configParserSettings) { auto configPath = FindEngineRoot(registry) / filePath; - IO::SystemFile configFile; - if (!configFile.Open(configPath.c_str(), IO::SystemFile::OpenMode::SF_OPEN_READ_ONLY)) + IO::FileReader configFile; + bool configFileOpened{}; + switch (configParserSettings.m_fileReaderClass) + { + case ConfigParserSettings::FileReaderClass::UseFileIOIfAvailableFallbackToSystemFile: + { + auto fileIo = AZ::IO::FileIOBase::GetInstance(); + configFileOpened = configFile.Open(fileIo, configPath.c_str()); + break; + } + case ConfigParserSettings::FileReaderClass::UseSystemFileOnly: + { + configFileOpened = configFile.Open(nullptr, configPath.c_str()); + break; + } + case ConfigParserSettings::FileReaderClass::UseFileIOOnly: + { + auto fileIo = AZ::IO::FileIOBase::GetInstance(); + if (fileIo == nullptr) + { + return false; + } + configFileOpened = configFile.Open(fileIo, configPath.c_str()); + break; + } + default: + AZ_Error("SettingsRegistryMergeUtils", false, "An Invalid FileReaderClass enum value has been supplied"); + return false; + } + if (!configFileOpened) { AZ_Warning("SettingsRegistryMergeUtils", false, R"(Unable to open file "%s")", configPath.c_str()); return false; @@ -480,7 +510,7 @@ namespace AZ::SettingsRegistryMergeUtils AZ_Error("SettingsRegistryMergeUtils", false, R"(The config file "%s" contains a line which is longer than the max line length of %zu.)" "\n" R"(Parsing will halt. The line content so far is:)" "\n" - R"("%.*s")" "\n", configFile.Name(), configBuffer.max_size(), + R"("%.*s")" "\n", configPath.c_str(), configBuffer.max_size(), aznumeric_cast(configBuffer.size()), configBuffer.data()); configFileParsed = false; break; diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h index 02346c2ba1..daa64c0343 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h @@ -155,6 +155,15 @@ namespace AZ::SettingsRegistryMergeUtils //! structure which is forwarded to the SettingsRegistryInterface MergeCommandLineArgument function //! The structure contains a functor which returns true if a character is a valid delimiter SettingsRegistryInterface::CommandLineArgumentSettings m_commandLineSettings; + + //! enumeration to indicate if AZ::IO::FileIOBase should be used to open the config file over AZ::IO::SystemFile + enum class FileReaderClass + { + UseFileIOIfAvailableFallbackToSystemFile, + UseSystemFileOnly, + UseFileIOOnly + }; + FileReaderClass m_fileReaderClass = FileReaderClass::UseFileIOIfAvailableFallbackToSystemFile; }; //! Loads basic configuration files which have structures similar to Windows INI files //! It is inspired by the Python configparser module: https://docs.python.org/3.10/library/configparser.html diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index 6c498c3335..aa07959997 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -166,6 +166,8 @@ set(FILES IO/FileIO.cpp IO/FileIO.h IO/FileIOEventBus.h + IO/FileReader.cpp + IO/FileReader.h IO/IOUtils.h IO/IOUtils.cpp IO/IStreamer.h diff --git a/Code/Framework/AzCore/Tests/IO/FileReaderTests.cpp b/Code/Framework/AzCore/Tests/IO/FileReaderTests.cpp new file mode 100644 index 0000000000..691b3f2821 --- /dev/null +++ b/Code/Framework/AzCore/Tests/IO/FileReaderTests.cpp @@ -0,0 +1,72 @@ +/* + * 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 +{ + template + class FileReaderTestFixture + : public ScopedAllocatorSetupFixture + { + public: + void SetUp() override + { + if constexpr (AZStd::is_same_v) + { + m_fileIo = AZStd::make_unique(); + } + } + + void TearDown() override + { + m_fileIo.reset(); + } + + protected: + AZStd::unique_ptr m_fileIo{}; + }; + + using FileIOTypes = ::testing::Types; + + TYPED_TEST_CASE(FileReaderTestFixture, FileIOTypes); + + TYPED_TEST(FileReaderTestFixture, ConstructorWithFilePath_OpensFileSuccessfully) + { + AZ::IO::FileReader fileReader(this->m_fileIo.get(), AZ::IO::SystemFile::GetNullFilename()); + EXPECT_TRUE(fileReader.IsOpen()); + } + + TYPED_TEST(FileReaderTestFixture, Open_OpensFileSucessfully) + { + AZ::IO::FileReader fileReader; + fileReader.Open(this->m_fileIo.get(), AZ::IO::SystemFile::GetNullFilename()); + EXPECT_TRUE(fileReader.IsOpen()); + } + + TYPED_TEST(FileReaderTestFixture, Eof_OnNULDeviceFile_Succeeds) + { + AZ::IO::FileReader fileReader(this->m_fileIo.get(), AZ::IO::SystemFile::GetNullFilename()); + EXPECT_TRUE(fileReader.Eof()); + } + + TYPED_TEST(FileReaderTestFixture, GetFilePath_ReturnsNULDeviceFilename_Succeeds) + { + AZ::IO::FileReader fileReader(this->m_fileIo.get(), AZ::IO::SystemFile::GetNullFilename()); + AZ::IO::FixedMaxPath filePath; + EXPECT_TRUE(fileReader.GetFilePath(filePath)); + AZ::IO::FixedMaxPath nulFilename{ AZ::IO::SystemFile::GetNullFilename() }; + if (this->m_fileIo) + { + EXPECT_TRUE(this->m_fileIo->ResolvePath(nulFilename, nulFilename)); + } + EXPECT_EQ(nulFilename, filePath); + } + +} // namespace UnitTest diff --git a/Code/Framework/AzCore/Tests/azcoretests_files.cmake b/Code/Framework/AzCore/Tests/azcoretests_files.cmake index d4d107f094..c36d37d874 100644 --- a/Code/Framework/AzCore/Tests/azcoretests_files.cmake +++ b/Code/Framework/AzCore/Tests/azcoretests_files.cmake @@ -37,6 +37,7 @@ set(FILES FileIOBaseTestTypes.h Geometry2DUtils.cpp Interface.cpp + IO/FileReaderTests.cpp IO/Path/PathTests.cpp IPC.cpp Jobs.cpp diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index 9ee05425ef..7d4ca36458 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -116,6 +116,12 @@ namespace AzToolsFramework::Prefab bool PrefabFocusHandler::IsOwningPrefabBeingFocused(AZ::EntityId entityId) { + if (!m_focusedInstance.has_value()) + { + // PrefabFocusHandler has not been initialized yet. + return false; + } + if (entityId == AZ::EntityId()) { return false; diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index 30117d6636..957b2b4fa6 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -498,6 +498,18 @@ QProgressBar::chunk { font-size: 10px; } +/************** Gems SubWidget **************/ + +#gemSubWidgetTitleLabel { + color: #FFFFFF; + font-size: 16px; +} + +#gemSubWidgetTextLabel { + color: #DDDDDD; + font-size: 10px; +} + /************** Gem Catalog (Inspector) **************/ #GemCatalogInspector { @@ -597,3 +609,20 @@ QProgressBar::chunk { #gemRepoInspector { background: #444444; } + +/************** Gem Repo Inspector **************/ + +#gemRepoInspectorNameLabel { + font-size: 18px; + color: #FFFFFF; +} + +#gemRepoInspectorBodyLabel { + font-size: 12px; + color: #DDDDDD; +} + +#gemRepoInspectorAddInfoTitleLabel { + font-size: 16px; + color: #FFFFFF; +} \ No newline at end of file diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp index 909cd93cda..9fca6040d4 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -23,7 +24,7 @@ namespace O3DE::ProjectManager m_layout = new QVBoxLayout(); m_layout->setSpacing(0); - m_layout->setMargin(0); + m_layout->setMargin(5); m_layout->setAlignment(Qt::AlignTop); setLayout(m_layout); @@ -41,74 +42,111 @@ namespace O3DE::ProjectManager hLayout->addWidget(closeButton); m_layout->addLayout(hLayout); - // enabled - { - m_enabledWidget = new QWidget(); - m_enabledWidget->setFixedWidth(s_width); - m_layout->addWidget(m_enabledWidget); + // added + CreateGemSection( tr("Gem to be activated"), tr("Gems to be activated"), [=] + { + QVector gems; + const QVector toBeAdded = m_gemModel->GatherGemsToBeAdded(/*includeDependencies=*/false); - QVBoxLayout* layout = new QVBoxLayout(); - layout->setAlignment(Qt::AlignTop); - m_enabledWidget->setLayout(layout); + // don't include gems that were already active because they were dependencies + for (const QModelIndex& modelIndex : toBeAdded) + { + if (!GemModel::WasPreviouslyAddedDependency(modelIndex)) + { + gems.push_back(modelIndex); + } + } + return gems; + }); - m_enabledLabel = new QLabel(); - m_enabledLabel->setObjectName("GemCatalogCartOverlaySectionLabel"); - layout->addWidget(m_enabledLabel); - m_enabledTagContainer = new TagContainerWidget(); - layout->addWidget(m_enabledTagContainer); - } + // removed + CreateGemSection( tr("Gem to be deactivated"), tr("Gems to be deactivated"), [=] + { + QVector gems; + const QVector toBeAdded = m_gemModel->GatherGemsToBeRemoved(/*includeDependencies=*/false); - // disabled - { - m_disabledWidget = new QWidget(); - m_disabledWidget->setFixedWidth(s_width); - m_layout->addWidget(m_disabledWidget); + // don't include gems that are still active because they are dependencies + for (const QModelIndex& modelIndex : toBeAdded) + { + if (!GemModel::IsAddedDependency(modelIndex)) + { + gems.push_back(modelIndex); + } + } + return gems; + }); - QVBoxLayout* layout = new QVBoxLayout(); - layout->setAlignment(Qt::AlignTop); - m_disabledWidget->setLayout(layout); + // added dependencies + CreateGemSection( tr("Dependency to be activated"), tr("Dependencies to be activated"), [=] + { + QVector dependencies; + const QVector toBeAdded = m_gemModel->GatherGemsToBeAdded(/*includeDependencies=*/true); - m_disabledLabel = new QLabel(); - m_disabledLabel->setObjectName("GemCatalogCartOverlaySectionLabel"); - layout->addWidget(m_disabledLabel); - m_disabledTagContainer = new TagContainerWidget(); - layout->addWidget(m_disabledTagContainer); - } + // only include gems that are dependencies and not explicitly added + for (const QModelIndex& modelIndex : toBeAdded) + { + if (GemModel::IsAddedDependency(modelIndex) && !GemModel::IsAdded(modelIndex)) + { + dependencies.push_back(modelIndex); + } + } + return dependencies; + }); + + // removed dependencies + CreateGemSection( tr("Dependency to be deactivated"), tr("Dependencies to be deactivated"), [=] + { + QVector dependencies; + const QVector toBeRemoved = m_gemModel->GatherGemsToBeRemoved(/*includeDependencies=*/true); + + // don't include gems that were explicitly removed - those are listed in a different section + for (const QModelIndex& modelIndex : toBeRemoved) + { + if (!GemModel::WasPreviouslyAdded(modelIndex)) + { + dependencies.push_back(modelIndex); + } + } + return dependencies; + }); setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog); - - Update(); - connect(gemModel, &GemModel::dataChanged, this, [=] - { - Update(); - }); } - void CartOverlayWidget::Update() + void CartOverlayWidget::CreateGemSection(const QString& singularTitle, const QString& pluralTitle, GetTagIndicesCallback getTagIndices) { - const QVector toBeAdded = m_gemModel->GatherGemsToBeAdded(); - if (toBeAdded.isEmpty()) - { - m_enabledWidget->hide(); - } - else - { - m_enabledTagContainer->Update(ConvertFromModelIndices(toBeAdded)); - m_enabledLabel->setText(QString("%1 %2").arg(QString::number(toBeAdded.size()), tr("Gems to be enabled"))); - m_enabledWidget->show(); - } + QWidget* widget = new QWidget(); + widget->setFixedWidth(s_width); + m_layout->addWidget(widget); - const QVector toBeRemoved = m_gemModel->GatherGemsToBeRemoved(); - if (toBeRemoved.isEmpty()) + QVBoxLayout* layout = new QVBoxLayout(); + layout->setAlignment(Qt::AlignTop); + widget->setLayout(layout); + + QLabel* label = new QLabel(); + label->setObjectName("GemCatalogCartOverlaySectionLabel"); + layout->addWidget(label); + + TagContainerWidget* tagContainer = new TagContainerWidget(); + layout->addWidget(tagContainer); + + auto update = [=]() { - m_disabledWidget->hide(); - } - else - { - m_disabledTagContainer->Update(ConvertFromModelIndices(toBeRemoved)); - m_disabledLabel->setText(QString("%1 %2").arg(QString::number(toBeRemoved.size()), tr("Gems to be disabled"))); - m_disabledWidget->show(); - } + const QVector tagIndices = getTagIndices(); + if (tagIndices.isEmpty()) + { + widget->hide(); + } + else + { + tagContainer->Update(ConvertFromModelIndices(tagIndices)); + label->setText(QString("%1 %2").arg(tagIndices.size()).arg(tagIndices.size() == 1 ? singularTitle : pluralTitle)); + widget->show(); + } + }; + + connect(m_gemModel, &GemModel::dataChanged, this, update); + update(); } QStringList CartOverlayWidget::ConvertFromModelIndices(const QVector& gems) const @@ -154,15 +192,15 @@ namespace O3DE::ProjectManager // Adjust the label text whenever the model gets updated. connect(gemModel, &GemModel::dataChanged, [=] { - const QVector toBeAdded = m_gemModel->GatherGemsToBeAdded(); - const QVector toBeRemoved = m_gemModel->GatherGemsToBeRemoved(); + const QVector toBeAdded = m_gemModel->GatherGemsToBeAdded(/*includeDependencies=*/true); + const QVector toBeRemoved = m_gemModel->GatherGemsToBeRemoved(/*includeDependencies=*/true); const int count = toBeAdded.size() + toBeRemoved.size(); m_countLabel->setText(QString::number(count)); m_dropDownButton->setVisible(!toBeAdded.isEmpty() || !toBeRemoved.isEmpty()); - // Automatically close the overlay window in case there are no gems to be enabled or disabled anymore. + // Automatically close the overlay window in case there are no gems to be activated or deactivated anymore. if (m_cartOverlay && toBeAdded.isEmpty() && toBeRemoved.isEmpty()) { m_cartOverlay->deleteLater(); @@ -186,8 +224,8 @@ namespace O3DE::ProjectManager void CartButton::ShowOverlay() { - const QVector toBeAdded = m_gemModel->GatherGemsToBeAdded(); - const QVector toBeRemoved = m_gemModel->GatherGemsToBeRemoved(); + const QVector toBeAdded = m_gemModel->GatherGemsToBeAdded(/*includeDependencies=*/true); + const QVector toBeRemoved = m_gemModel->GatherGemsToBeRemoved(/*includeDependencies=*/true); if (toBeAdded.isEmpty() && toBeRemoved.isEmpty()) { return; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h index 4c21fbbbe3..2cfda4c790 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h @@ -8,6 +8,8 @@ #pragma once +#include + #if !defined(Q_MOC_RUN) #include #include @@ -30,22 +32,16 @@ namespace O3DE::ProjectManager public: CartOverlayWidget(GemModel* gemModel, QWidget* parent = nullptr); - void Update(); private: QStringList ConvertFromModelIndices(const QVector& gems) const; + using GetTagIndicesCallback = AZStd::function()>; + void CreateGemSection(const QString& singularTitle, const QString& pluralTitle, GetTagIndicesCallback getTagIndices); + QVBoxLayout* m_layout = nullptr; GemModel* m_gemModel = nullptr; - QWidget* m_enabledWidget = nullptr; - QLabel* m_enabledLabel = nullptr; - TagContainerWidget* m_enabledTagContainer = nullptr; - - QWidget* m_disabledWidget = nullptr; - QLabel* m_disabledLabel = nullptr; - TagContainerWidget* m_disabledTagContainer = nullptr; - inline constexpr static int s_width = 240; }; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 04d4d6999b..a41a81b448 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -100,6 +100,8 @@ namespace O3DE::ProjectManager m_gemModel->AddGem(gemInfo); } + m_gemModel->UpdateGemDependencies(); + // Gather enabled gems for the given project. auto enabledGemNamesResult = PythonBindingsInterface::Get()->GetEnabledGemNames(projectPath); if (enabledGemNamesResult.IsSuccess()) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp index c9ea138b55..b425c15dee 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp @@ -226,13 +226,20 @@ namespace O3DE::ProjectManager QVector elementCounts; const int totalGems = m_gemModel->rowCount(); const int selectedGemTotal = m_gemModel->TotalAddedGems(); + const int enabledGemTotal = m_gemModel->TotalAddedGems(/*includeDependencies=*/true); - elementNames.push_back(GemSortFilterProxyModel::GetGemStatusString(GemSortFilterProxyModel::GemStatus::Unselected)); + elementNames.push_back(GemSortFilterProxyModel::GetGemSelectedString(GemSortFilterProxyModel::GemSelected::Unselected)); elementCounts.push_back(totalGems - selectedGemTotal); - elementNames.push_back(GemSortFilterProxyModel::GetGemStatusString(GemSortFilterProxyModel::GemStatus::Selected)); + elementNames.push_back(GemSortFilterProxyModel::GetGemSelectedString(GemSortFilterProxyModel::GemSelected::Selected)); elementCounts.push_back(selectedGemTotal); + elementNames.push_back(GemSortFilterProxyModel::GetGemActiveString(GemSortFilterProxyModel::GemActive::Inactive)); + elementCounts.push_back(totalGems - enabledGemTotal); + + elementNames.push_back(GemSortFilterProxyModel::GetGemActiveString(GemSortFilterProxyModel::GemActive::Active)); + elementCounts.push_back(enabledGemTotal); + bool wasCollapsed = false; if (m_statusFilter) { @@ -253,48 +260,53 @@ namespace O3DE::ProjectManager m_statusFilter->deleteLater(); m_statusFilter = filterWidget; - const GemSortFilterProxyModel::GemStatus currentFilterState = m_filterProxyModel->GetGemStatus(); const QList buttons = m_statusFilter->GetButtonGroup()->buttons(); - for (int statusFilterIndex = 0; statusFilterIndex < buttons.size(); ++statusFilterIndex) + + QAbstractButton* unselectedButton = buttons[0]; + QAbstractButton* selectedButton = buttons[1]; + unselectedButton->setChecked(m_filterProxyModel->GetGemSelected() == GemSortFilterProxyModel::GemSelected::Unselected); + selectedButton->setChecked(m_filterProxyModel->GetGemSelected() == GemSortFilterProxyModel::GemSelected::Selected); + + auto updateGemSelection = [=]([[maybe_unused]] bool checked) { - const GemSortFilterProxyModel::GemStatus gemStatus = static_cast(statusFilterIndex); - QAbstractButton* button = buttons[statusFilterIndex]; - - if (static_cast(statusFilterIndex) == currentFilterState) + if (unselectedButton->isChecked() && !selectedButton->isChecked()) { - button->setChecked(true); + m_filterProxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::Unselected); } + else if (!unselectedButton->isChecked() && selectedButton->isChecked()) + { + m_filterProxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::Selected); + } + else + { + m_filterProxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::NoFilter); + } + }; + connect(unselectedButton, &QAbstractButton::toggled, this, updateGemSelection); + connect(selectedButton, &QAbstractButton::toggled, this, updateGemSelection); - connect( - button, &QAbstractButton::toggled, this, - [=](bool checked) - { - GemSortFilterProxyModel::GemStatus filterStatus = m_filterProxyModel->GetGemStatus(); - if (checked) - { - if (filterStatus == GemSortFilterProxyModel::GemStatus::NoFilter) - { - filterStatus = gemStatus; - } - else - { - filterStatus = GemSortFilterProxyModel::GemStatus::NoFilter; - } - } - else - { - if (filterStatus != gemStatus) - { - filterStatus = static_cast(!gemStatus); - } - else - { - filterStatus = GemSortFilterProxyModel::GemStatus::NoFilter; - } - } - m_filterProxyModel->SetGemStatus(filterStatus); - }); - } + QAbstractButton* inactiveButton = buttons[2]; + QAbstractButton* activeButton = buttons[3]; + inactiveButton->setChecked(m_filterProxyModel->GetGemActive() == GemSortFilterProxyModel::GemActive::Inactive); + activeButton->setChecked(m_filterProxyModel->GetGemActive() == GemSortFilterProxyModel::GemActive::Active); + + auto updateGemActive = [=]([[maybe_unused]] bool checked) + { + if (inactiveButton->isChecked() && !activeButton->isChecked()) + { + m_filterProxyModel->SetGemActive(GemSortFilterProxyModel::GemActive::Inactive); + } + else if (!inactiveButton->isChecked() && activeButton->isChecked()) + { + m_filterProxyModel->SetGemActive(GemSortFilterProxyModel::GemActive::Active); + } + else + { + m_filterProxyModel->SetGemActive(GemSortFilterProxyModel::GemActive::NoFilter); + } + }; + connect(inactiveButton, &QAbstractButton::toggled, this, updateGemActive); + connect(activeButton, &QAbstractButton::toggled, this, updateGemActive); } void GemFilterWidget::AddGemOriginFilter() @@ -487,7 +499,7 @@ namespace O3DE::ProjectManager const QString& feature = elementNames[i]; QAbstractButton* button = buttons[i]; - // Adjust the proxy model and enable or disable the clicked feature used for filtering. + // Adjust the proxy model and enable the clicked feature used for filtering. connect(button, &QAbstractButton::toggled, this, [=](bool checked) { QSet features = m_filterProxyModel->GetFeatures(); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h index 4312b08998..311eeb93f6 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h @@ -75,8 +75,7 @@ namespace O3DE::ProjectManager QString m_version = "Unknown Version"; QString m_lastUpdatedDate = "Unknown Date"; int m_binarySizeInKB = 0; - QStringList m_dependingGemUuids; - QStringList m_conflictingGemUuids; + QStringList m_dependencies; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp index 6dd6c52612..7630e92e88 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp @@ -8,6 +8,7 @@ #include #include + #include #include #include @@ -83,14 +84,13 @@ namespace O3DE::ProjectManager m_reqirementsTextLabel->hide(); } - // Depending and conflicting gems + // Depending gems m_dependingGems->Update("Depending Gems", "The following Gems will be automatically enabled with this Gem.", m_model->GetDependingGemNames(modelIndex)); - m_conflictingGems->Update("Conflicting Gems", "The following Gems will be automatically disabled with this Gem.", m_model->GetConflictingGemNames(modelIndex)); // Additional information m_versionLabel->setText(QString("Gem Version: %1").arg(m_model->GetVersion(modelIndex))); m_lastUpdatedLabel->setText(QString("Last Updated: %1").arg(m_model->GetLastUpdated(modelIndex))); - m_binarySizeLabel->setText(QString("Binary Size: %1 KB").arg(QString::number(m_model->GetBinarySizeInKB(modelIndex)))); + m_binarySizeLabel->setText(QString("Binary Size: %1 KB").arg(m_model->GetBinarySizeInKB(modelIndex))); m_mainWidget->adjustSize(); m_mainWidget->show(); @@ -173,15 +173,11 @@ namespace O3DE::ProjectManager m_mainLayout->addSpacing(20); - // Depending and conflicting gems + // Depending gems m_dependingGems = new GemsSubWidget(); m_mainLayout->addWidget(m_dependingGems); m_mainLayout->addSpacing(20); - m_conflictingGems = new GemsSubWidget(); - m_mainLayout->addWidget(m_conflictingGems); - m_mainLayout->addSpacing(20); - // Additional information QLabel* additionalInfoLabel = CreateStyledLabel(m_mainLayout, 14, s_headerColor); additionalInfoLabel->setText("Additional Information"); @@ -190,27 +186,4 @@ namespace O3DE::ProjectManager m_lastUpdatedLabel = CreateStyledLabel(m_mainLayout, 12, s_textColor); m_binarySizeLabel = CreateStyledLabel(m_mainLayout, 12, s_textColor); } - - GemInspector::GemsSubWidget::GemsSubWidget(QWidget* parent) - : QWidget(parent) - { - m_layout = new QVBoxLayout(); - m_layout->setAlignment(Qt::AlignTop); - m_layout->setMargin(0); - setLayout(m_layout); - - m_titleLabel = GemInspector::CreateStyledLabel(m_layout, 16, s_headerColor); - m_textLabel = GemInspector::CreateStyledLabel(m_layout, 10, s_textColor); - m_textLabel->setWordWrap(true); - - m_tagWidget = new TagContainerWidget(); - m_layout->addWidget(m_tagWidget); - } - - void GemInspector::GemsSubWidget::Update(const QString& title, const QString& text, const QStringList& gemNames) - { - m_titleLabel->setText(title); - m_textLabel->setText(text); - m_tagWidget->Update(gemNames); - } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h index 97c23f7df2..ca36cef240 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h @@ -9,10 +9,11 @@ #pragma once #if !defined(Q_MOC_RUN) -#include -#include #include #include +#include +#include + #include #include #include @@ -43,21 +44,6 @@ namespace O3DE::ProjectManager void OnSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); private: - // Title, description and tag widget container used for the depending and conflicting gems - class GemsSubWidget - : public QWidget - { - public: - GemsSubWidget(QWidget* parent = nullptr); - void Update(const QString& title, const QString& text, const QStringList& gemNames); - - private: - QLabel* m_titleLabel = nullptr; - QLabel* m_textLabel = nullptr; - QVBoxLayout* m_layout = nullptr; - TagContainerWidget* m_tagWidget = nullptr; - }; - void InitMainWidget(); GemModel* m_model = nullptr; @@ -78,7 +64,6 @@ namespace O3DE::ProjectManager // Depending and conflicting gems GemsSubWidget* m_dependingGems = nullptr; - GemsSubWidget* m_conflictingGems = nullptr; // Additional information QLabel* m_versionLabel = nullptr; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp index 99a2cd8db7..dc24c13009 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp @@ -8,9 +8,14 @@ #include #include +#include #include +#include #include #include +#include +#include +#include namespace O3DE::ProjectManager { @@ -149,8 +154,7 @@ namespace O3DE::ProjectManager return true; } } - - if (event->type() == QEvent::MouseButtonPress) + else if (event->type() == QEvent::MouseButtonPress ) { QMouseEvent* mouseEvent = static_cast(event); @@ -169,6 +173,69 @@ namespace O3DE::ProjectManager return QStyledItemDelegate::editorEvent(event, model, option, modelIndex); } + QString GetGemNameList(const QVector modelIndices) + { + QString gemNameList; + for (int i = 0; i < modelIndices.size(); ++i) + { + if (!gemNameList.isEmpty()) + { + if (i == modelIndices.size() - 1) + { + gemNameList.append(" and "); + } + else + { + gemNameList.append(", "); + } + } + + gemNameList.append(GemModel::GetDisplayName(modelIndices[i])); + } + + return gemNameList; + } + + bool GemItemDelegate::helpEvent(QHelpEvent* event, QAbstractItemView* view, const QStyleOptionViewItem& option, const QModelIndex& index) + { + if (event->type() == QEvent::ToolTip) + { + QRect fullRect, itemRect, contentRect; + CalcRects(option, fullRect, itemRect, contentRect); + const QRect buttonRect = CalcButtonRect(contentRect); + if (buttonRect.contains(event->pos())) + { + if (!QToolTip::isVisible()) + { + if(GemModel::IsAddedDependency(index) && !GemModel::IsAdded(index)) + { + const GemModel* gemModel = GemModel::GetSourceModel(index.model()); + AZ_Assert(gemModel, "Failed to obtain GemModel"); + + // we only want to display the gems that must be de-selected to automatically + // disable this dependency, so don't include any that haven't been selected (added) + constexpr bool addedOnly = true; + QVector dependents = gemModel->GatherDependentGems(index, addedOnly); + QString nameList = GetGemNameList(dependents); + if (!nameList.isEmpty()) + { + QToolTip::showText(event->globalPos(), tr("This gem is a dependency of %1.\nTo disable this gem, first disable %1.").arg(nameList)); + } + } + } + return true; + } + else if (QToolTip::isVisible()) + { + QToolTip::hideText(); + event->ignore(); + return true; + } + } + + return QStyledItemDelegate::helpEvent(event, view, option, index); + } + void GemItemDelegate::CalcRects(const QStyleOptionViewItem& option, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const { outFullRect = QRect(option.rect); @@ -260,14 +327,20 @@ namespace O3DE::ProjectManager const QRect buttonRect = CalcButtonRect(contentRect); QPoint circleCenter; - const bool isAdded = GemModel::IsAdded(modelIndex); - if (isAdded) + if (GemModel::IsAdded(modelIndex)) { painter->setBrush(m_buttonEnabledColor); painter->setPen(m_buttonEnabledColor); circleCenter = buttonRect.center() + QPoint(buttonRect.width() / 2 - s_buttonBorderRadius + 1, 1); } + else if (GemModel::IsAddedDependency(modelIndex)) + { + painter->setBrush(m_buttonImplicitlyEnabledColor); + painter->setPen(m_buttonImplicitlyEnabledColor); + + circleCenter = buttonRect.center() + QPoint(buttonRect.width() / 2 - s_buttonBorderRadius + 1, 1); + } else { circleCenter = buttonRect.center() + QPoint(-buttonRect.width() / 2 + s_buttonBorderRadius, 1); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h index a0a3dbb36a..d842f63ae7 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h @@ -29,7 +29,6 @@ namespace O3DE::ProjectManager ~GemItemDelegate() = default; void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override; - bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) override; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override; // Colors @@ -39,6 +38,7 @@ namespace O3DE::ProjectManager const QColor m_itemBackgroundColor = QColor("#404040"); // Background color of the gem item const QColor m_borderColor = QColor("#1E70EB"); const QColor m_buttonEnabledColor = QColor("#00B931"); + const QColor m_buttonImplicitlyEnabledColor = QColor("#BCBCBE"); // Item inline constexpr static int s_height = 105; // Gem item total height @@ -65,6 +65,9 @@ namespace O3DE::ProjectManager inline constexpr static int s_featureTagSpacing = 7; protected: + bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) override; + bool helpEvent(QHelpEvent* event, QAbstractItemView* view, const QStyleOptionViewItem& option, const QModelIndex& index) override; + void CalcRects(const QStyleOptionViewItem& option, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const; QRect GetTextRect(QFont& font, const QString& text, qreal fontSize) const; QRect CalcButtonRect(const QRect& contentRect) const; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp index 16234f4900..ab51c7511c 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp @@ -60,11 +60,14 @@ namespace O3DE::ProjectManager QLabel* showCountLabel = new QLabel(); showCountLabel->setObjectName("GemCatalogHeaderShowCountLabel"); topLayout->addWidget(showCountLabel); - connect(proxyModel, &GemSortFilterProxyModel::OnInvalidated, this, [=] - { + + auto refreshGemCountUI = [=]() { const int numGemsShown = proxyModel->rowCount(); showCountLabel->setText(QString(tr("showing %1 Gems")).arg(numGemsShown)); - }); + }; + + connect(proxyModel, &GemSortFilterProxyModel::OnInvalidated, this, refreshGemCountUI); + connect(proxyModel->GetSourceModel(), &GemModel::dataChanged, this, refreshGemCountUI); topLayout->addSpacing(GemItemDelegate::s_contentMargins.right() + GemItemDelegate::s_borderWidth); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp index d393a30ed9..afdb9697c9 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp @@ -9,9 +9,26 @@ #include #include #include +#include namespace O3DE::ProjectManager { + class GemListViewProxyStyle : public QProxyStyle + { + public: + using QProxyStyle::QProxyStyle; + int styleHint(StyleHint hint, const QStyleOption* option = nullptr, const QWidget* widget = nullptr, QStyleHintReturn* returnData = nullptr) const override + { + if (hint == QStyle::SH_ToolTip_WakeUpDelay || hint == QStyle::SH_ToolTip_FallAsleepDelay) + { + // no delay + return 0; + } + + return QProxyStyle::styleHint(hint, option, widget, returnData); + } + }; + GemListView::GemListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent) : QListView(parent) { @@ -21,5 +38,8 @@ namespace O3DE::ProjectManager setModel(model); setSelectionModel(selectionModel); setItemDelegate(new GemItemDelegate(model, this)); + + // use a custom proxy style so we get immediate tooltips for gem radio buttons + setStyle(new GemListViewProxyStyle(this->style())); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index 7daea174e7..0941541793 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -8,6 +8,7 @@ #include #include +#include #include namespace O3DE::ProjectManager @@ -40,8 +41,7 @@ namespace O3DE::ProjectManager item->setData(gemInfo.m_isAdded, RoleIsAdded); item->setData(gemInfo.m_directoryLink, RoleDirectoryLink); item->setData(gemInfo.m_documentationLink, RoleDocLink); - item->setData(gemInfo.m_dependingGemUuids, RoleDependingGems); - item->setData(gemInfo.m_conflictingGemUuids, RoleConflictingGems); + item->setData(gemInfo.m_dependencies, RoleDependingGems); item->setData(gemInfo.m_version, RoleVersion); item->setData(gemInfo.m_lastUpdatedDate, RoleLastUpdated); item->setData(gemInfo.m_binarySizeInKB, RoleBinarySize); @@ -60,6 +60,39 @@ namespace O3DE::ProjectManager clear(); } + void GemModel::UpdateGemDependencies() + { + m_gemDependencyMap.clear(); + m_gemReverseDependencyMap.clear(); + + for (auto iter = m_nameToIndexMap.begin(); iter != m_nameToIndexMap.end(); ++iter) + { + const QString& key = iter.key(); + const QModelIndex modelIndex = iter.value(); + QSet dependencies; + GetAllDependingGems(modelIndex, dependencies); + if (!dependencies.isEmpty()) + { + m_gemDependencyMap.insert(key, dependencies); + } + } + + for (auto iter = m_gemDependencyMap.begin(); iter != m_gemDependencyMap.end(); ++iter) + { + const QString& dependant = iter.key(); + for (const QModelIndex& dependency : iter.value()) + { + const QString& dependencyName = dependency.data(RoleName).toString(); + if (!m_gemReverseDependencyMap.contains(dependencyName)) + { + m_gemReverseDependencyMap.insert(dependencyName, QSet()); + } + + m_gemReverseDependencyMap[dependencyName].insert(m_nameToIndexMap[dependant]); + } + } + } + QString GemModel::GetName(const QModelIndex& modelIndex) { return modelIndex.data(RoleName).toString(); @@ -125,49 +158,46 @@ namespace O3DE::ProjectManager return {}; } - void GemModel::FindGemNamesByNameStrings(QStringList& inOutGemNames) + void GemModel::FindGemDisplayNamesByNameStrings(QStringList& inOutGemNames) { - for (QString& dependingGemString : inOutGemNames) + for (QString& name : inOutGemNames) { - QModelIndex modelIndex = FindIndexByNameString(dependingGemString); + QModelIndex modelIndex = FindIndexByNameString(name); if (modelIndex.isValid()) { - dependingGemString = GetDisplayName(modelIndex); + name = GetDisplayName(modelIndex); } } } - QStringList GemModel::GetDependingGemUuids(const QModelIndex& modelIndex) + QStringList GemModel::GetDependingGems(const QModelIndex& modelIndex) { return modelIndex.data(RoleDependingGems).toStringList(); } + void GemModel::GetAllDependingGems(const QModelIndex& modelIndex, QSet& inOutGems) + { + QStringList dependencies = GetDependingGems(modelIndex); + for (const QString& dependency : dependencies) + { + QModelIndex dependencyIndex = FindIndexByNameString(dependency); + if (!inOutGems.contains(dependencyIndex)) + { + inOutGems.insert(dependencyIndex); + GetAllDependingGems(dependencyIndex, inOutGems); + } + } + } + QStringList GemModel::GetDependingGemNames(const QModelIndex& modelIndex) { - QStringList result = GetDependingGemUuids(modelIndex); + QStringList result = GetDependingGems(modelIndex); if (result.isEmpty()) { return {}; } - FindGemNamesByNameStrings(result); - return result; - } - - QStringList GemModel::GetConflictingGemUuids(const QModelIndex& modelIndex) - { - return modelIndex.data(RoleConflictingGems).toStringList(); - } - - QStringList GemModel::GetConflictingGemNames(const QModelIndex& modelIndex) - { - QStringList result = GetConflictingGemUuids(modelIndex); - if (result.isEmpty()) - { - return {}; - } - - FindGemNamesByNameStrings(result); + FindGemDisplayNamesByNameStrings(result); return result; } @@ -201,29 +231,146 @@ namespace O3DE::ProjectManager return modelIndex.data(RoleRequirement).toString(); } + GemModel* GemModel::GetSourceModel(QAbstractItemModel* model) + { + GemSortFilterProxyModel* proxyModel = qobject_cast(model); + if (proxyModel) + { + return proxyModel->GetSourceModel(); + } + else + { + return qobject_cast(model); + } + } + + const GemModel* GemModel::GetSourceModel(const QAbstractItemModel* model) + { + const GemSortFilterProxyModel* proxyModel = qobject_cast(model); + if (proxyModel) + { + return proxyModel->GetSourceModel(); + } + else + { + return qobject_cast(model); + } + } + bool GemModel::IsAdded(const QModelIndex& modelIndex) { return modelIndex.data(RoleIsAdded).toBool(); } + bool GemModel::IsAddedDependency(const QModelIndex& modelIndex) + { + return modelIndex.data(RoleIsAddedDependency).toBool(); + } + void GemModel::SetIsAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isAdded) { model.setData(modelIndex, isAdded, RoleIsAdded); + + UpdateDependencies(model, modelIndex); + } + + bool GemModel::HasDependentGems(const QModelIndex& modelIndex) const + { + QVector dependentGems = GatherDependentGems(modelIndex); + for (const QModelIndex& dependency : dependentGems) + { + if (IsAdded(dependency)) + { + return true; + } + } + return false; + } + + void GemModel::UpdateDependencies(QAbstractItemModel& model, const QModelIndex& modelIndex) + { + GemModel* gemModel = GetSourceModel(&model); + AZ_Assert(gemModel, "Failed to obtain GemModel"); + + QVector dependencies = gemModel->GatherGemDependencies(modelIndex); + if (IsAdded(modelIndex)) + { + for (const QModelIndex& dependency : dependencies) + { + SetIsAddedDependency(*gemModel, dependency, true); + } + } + else + { + // still a dependency if some added gem depends on this one + SetIsAddedDependency(model, modelIndex, gemModel->HasDependentGems(modelIndex)); + + for (const QModelIndex& dependency : dependencies) + { + SetIsAddedDependency(*gemModel, dependency, gemModel->HasDependentGems(dependency)); + } + } + } + + void GemModel::SetIsAddedDependency(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isAdded) + { + model.setData(modelIndex, isAdded, RoleIsAddedDependency); } void GemModel::SetWasPreviouslyAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool wasAdded) { model.setData(modelIndex, wasAdded, RoleWasPreviouslyAdded); + + if (wasAdded) + { + // update all dependencies + GemModel* gemModel = GetSourceModel(&model); + AZ_Assert(gemModel, "Failed to obtain GemModel"); + QVector dependencies = gemModel->GatherGemDependencies(modelIndex); + for (const QModelIndex& dependency : dependencies) + { + SetWasPreviouslyAddedDependency(*gemModel, dependency, true); + } + } } - bool GemModel::NeedsToBeAdded(const QModelIndex& modelIndex) + void GemModel::SetWasPreviouslyAddedDependency(QAbstractItemModel& model, const QModelIndex& modelIndex, bool wasAdded) { - return (!modelIndex.data(RoleWasPreviouslyAdded).toBool() && modelIndex.data(RoleIsAdded).toBool()); + model.setData(modelIndex, wasAdded, RoleWasPreviouslyAddedDependency); } - bool GemModel::NeedsToBeRemoved(const QModelIndex& modelIndex) + bool GemModel::WasPreviouslyAdded(const QModelIndex& modelIndex) { - return (modelIndex.data(RoleWasPreviouslyAdded).toBool() && !modelIndex.data(RoleIsAdded).toBool()); + return modelIndex.data(RoleWasPreviouslyAdded).toBool(); + } + + bool GemModel::WasPreviouslyAddedDependency(const QModelIndex& modelIndex) + { + return modelIndex.data(RoleWasPreviouslyAddedDependency).toBool(); + } + + bool GemModel::NeedsToBeAdded(const QModelIndex& modelIndex, bool includeDependencies) + { + bool previouslyAdded = modelIndex.data(RoleWasPreviouslyAdded).toBool(); + bool added = modelIndex.data(RoleIsAdded).toBool(); + if (includeDependencies) + { + previouslyAdded |= modelIndex.data(RoleWasPreviouslyAddedDependency).toBool(); + added |= modelIndex.data(RoleIsAddedDependency).toBool(); + } + return !previouslyAdded && added; + } + + bool GemModel::NeedsToBeRemoved(const QModelIndex& modelIndex, bool includeDependencies) + { + bool previouslyAdded = modelIndex.data(RoleWasPreviouslyAdded).toBool(); + bool added = modelIndex.data(RoleIsAdded).toBool(); + if (includeDependencies) + { + previouslyAdded |= modelIndex.data(RoleWasPreviouslyAddedDependency).toBool(); + added |= modelIndex.data(RoleIsAddedDependency).toBool(); + } + return previouslyAdded && !added; } bool GemModel::HasRequirement(const QModelIndex& modelIndex) @@ -244,13 +391,44 @@ namespace O3DE::ProjectManager return false; } - QVector GemModel::GatherGemsToBeAdded() const + QVector GemModel::GatherGemDependencies(const QModelIndex& modelIndex) const + { + QVector result; + const QString& gemName = modelIndex.data(RoleName).toString(); + if (m_gemDependencyMap.contains(gemName)) + { + for (const QModelIndex& dependency : m_gemDependencyMap[gemName]) + { + result.push_back(dependency); + } + } + return result; + } + + QVector GemModel::GatherDependentGems(const QModelIndex& modelIndex, bool addedOnly) const + { + QVector result; + const QString& gemName = modelIndex.data(RoleName).toString(); + if (m_gemReverseDependencyMap.contains(gemName)) + { + for (const QModelIndex& dependency : m_gemReverseDependencyMap[gemName]) + { + if (!addedOnly || GemModel::IsAdded(dependency)) + { + result.push_back(dependency); + } + } + } + return result; + } + + QVector GemModel::GatherGemsToBeAdded(bool includeDependencies) const { QVector result; for (int row = 0; row < rowCount(); ++row) { const QModelIndex modelIndex = index(row, 0); - if (NeedsToBeAdded(modelIndex)) + if (NeedsToBeAdded(modelIndex, includeDependencies)) { result.push_back(modelIndex); } @@ -258,13 +436,13 @@ namespace O3DE::ProjectManager return result; } - QVector GemModel::GatherGemsToBeRemoved() const + QVector GemModel::GatherGemsToBeRemoved(bool includeDependencies) const { QVector result; for (int row = 0; row < rowCount(); ++row) { const QModelIndex modelIndex = index(row, 0); - if (NeedsToBeRemoved(modelIndex)) + if (NeedsToBeRemoved(modelIndex, includeDependencies)) { result.push_back(modelIndex); } @@ -272,13 +450,13 @@ namespace O3DE::ProjectManager return result; } - int GemModel::TotalAddedGems() const + int GemModel::TotalAddedGems(bool includeDependencies) const { int result = 0; for (int row = 0; row < rowCount(); ++row) { const QModelIndex modelIndex = index(row, 0); - if (IsAdded(modelIndex)) + if (IsAdded(modelIndex) || (includeDependencies && IsAddedDependency(modelIndex))) { ++result; } diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h index ce004ee875..0591094c11 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h @@ -28,13 +28,11 @@ namespace O3DE::ProjectManager void AddGem(const GemInfo& gemInfo); void Clear(); + void UpdateGemDependencies(); QModelIndex FindIndexByNameString(const QString& nameString) const; - void FindGemNamesByNameStrings(QStringList& inOutGemNames); - QStringList GetDependingGemUuids(const QModelIndex& modelIndex); QStringList GetDependingGemNames(const QModelIndex& modelIndex); - QStringList GetConflictingGemUuids(const QModelIndex& modelIndex); - QStringList GetConflictingGemNames(const QModelIndex& modelIndex); + bool HasDependentGems(const QModelIndex& modelIndex) const; static QString GetName(const QModelIndex& modelIndex); static QString GetDisplayName(const QModelIndex& modelIndex); @@ -51,22 +49,36 @@ namespace O3DE::ProjectManager static QStringList GetFeatures(const QModelIndex& modelIndex); static QString GetPath(const QModelIndex& modelIndex); static QString GetRequirement(const QModelIndex& modelIndex); + static GemModel* GetSourceModel(QAbstractItemModel* model); + static const GemModel* GetSourceModel(const QAbstractItemModel* model); static bool IsAdded(const QModelIndex& modelIndex); + static bool IsAddedDependency(const QModelIndex& modelIndex); static void SetIsAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isAdded); + static void SetIsAddedDependency(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isAdded); static void SetWasPreviouslyAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool wasAdded); - static bool NeedsToBeAdded(const QModelIndex& modelIndex); - static bool NeedsToBeRemoved(const QModelIndex& modelIndex); + static bool WasPreviouslyAdded(const QModelIndex& modelIndex); + static void SetWasPreviouslyAddedDependency(QAbstractItemModel& model, const QModelIndex& modelIndex, bool wasAdded); + static bool WasPreviouslyAddedDependency(const QModelIndex& modelIndex); + static bool NeedsToBeAdded(const QModelIndex& modelIndex, bool includeDependencies = false); + static bool NeedsToBeRemoved(const QModelIndex& modelIndex, bool includeDependencies = false); static bool HasRequirement(const QModelIndex& modelIndex); + static void UpdateDependencies(QAbstractItemModel& model, const QModelIndex& modelIndex); bool DoGemsToBeAddedHaveRequirements() const; - QVector GatherGemsToBeAdded() const; - QVector GatherGemsToBeRemoved() const; + QVector GatherGemDependencies(const QModelIndex& modelIndex) const; + QVector GatherDependentGems(const QModelIndex& modelIndex, bool addedOnly = false) const; + QVector GatherGemsToBeAdded(bool includeDependencies = false) const; + QVector GatherGemsToBeRemoved(bool includeDependencies = false) const; - int TotalAddedGems() const; + int TotalAddedGems(bool includeDependencies = false) const; private: + void FindGemDisplayNamesByNameStrings(QStringList& inOutGemNames); + void GetAllDependingGems(const QModelIndex& modelIndex, QSet& inOutGems); + QStringList GetDependingGems(const QModelIndex& modelIndex); + enum UserRole { RoleName = Qt::UserRole, @@ -76,11 +88,12 @@ namespace O3DE::ProjectManager RolePlatforms, RoleSummary, RoleWasPreviouslyAdded, + RoleWasPreviouslyAddedDependency, RoleIsAdded, + RoleIsAddedDependency, RoleDirectoryLink, RoleDocLink, RoleDependingGems, - RoleConflictingGems, RoleVersion, RoleLastUpdated, RoleBinarySize, @@ -92,5 +105,7 @@ namespace O3DE::ProjectManager QHash m_nameToIndexMap; QItemSelectionModel* m_selectionModel = nullptr; + QHash> m_gemDependencyMap; + QHash> m_gemReverseDependencyMap; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp index 6edfced6e5..199692f200 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp @@ -50,11 +50,21 @@ namespace O3DE::ProjectManager } } - // Gem status - if (m_gemStatusFilter != GemStatus::NoFilter) + // Gem selected + if (m_gemSelectedFilter != GemSelected::NoFilter) { - const GemStatus sourceGemStatus = static_cast(GemModel::IsAdded(sourceIndex)); - if (m_gemStatusFilter != sourceGemStatus) + const GemSelected sourceGemStatus = static_cast(GemModel::IsAdded(sourceIndex)); + if (m_gemSelectedFilter != sourceGemStatus) + { + return false; + } + } + + // Gem enabled + if (m_gemActiveFilter != GemActive::NoFilter) + { + const GemActive sourceGemStatus = static_cast(GemModel::IsAdded(sourceIndex) || GemModel::IsAddedDependency(sourceIndex)); + if (m_gemActiveFilter != sourceGemStatus) { return false; } @@ -148,19 +158,31 @@ namespace O3DE::ProjectManager return true; } - QString GemSortFilterProxyModel::GetGemStatusString(GemStatus status) + QString GemSortFilterProxyModel::GetGemSelectedString(GemSelected status) { switch (status) { - case Unselected: + case GemSelected::Unselected: return "Unselected"; - case Selected: + case GemSelected::Selected: return "Selected"; default: - return ""; + return ""; } } + QString GemSortFilterProxyModel::GetGemActiveString(GemActive status) + { + switch (status) + { + case GemActive::Inactive: + return "Inactive"; + case GemActive::Active: + return "Active"; + default: + return ""; + } + } void GemSortFilterProxyModel::InvalidateFilter() { invalidate(); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h index 4ec170aef2..74b1e915eb 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h @@ -25,16 +25,23 @@ namespace O3DE::ProjectManager Q_OBJECT // AUTOMOC public: - enum GemStatus + enum class GemSelected { NoFilter = -1, Unselected, Selected }; + enum class GemActive + { + NoFilter = -1, + Inactive, + Active + }; GemSortFilterProxyModel(GemModel* sourceModel, QObject* parent = nullptr); - static QString GetGemStatusString(GemStatus status); + static QString GetGemSelectedString(GemSelected status); + static QString GetGemActiveString(GemActive status); bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override; @@ -43,8 +50,11 @@ namespace O3DE::ProjectManager void SetSearchString(const QString& searchString) { m_searchString = searchString; InvalidateFilter(); } - GemStatus GetGemStatus() const { return m_gemStatusFilter; } - void SetGemStatus(GemStatus gemStatus) { m_gemStatusFilter = gemStatus; InvalidateFilter(); } + GemSelected GetGemSelected() const { return m_gemSelectedFilter; } + void SetGemSelected(GemSelected selected) { m_gemSelectedFilter = selected; InvalidateFilter(); } + + GemActive GetGemActive() const { return m_gemActiveFilter; } + void SetGemActive(GemActive enabled) { m_gemActiveFilter = enabled; InvalidateFilter(); } GemInfo::GemOrigins GetGemOrigins() const { return m_gemOriginFilter; } void SetGemOrigins(const GemInfo::GemOrigins& gemOrigins) { m_gemOriginFilter = gemOrigins; InvalidateFilter(); } @@ -69,7 +79,8 @@ namespace O3DE::ProjectManager AzQtComponents::SelectionProxyModel* m_selectionProxyModel = nullptr; QString m_searchString; - GemStatus m_gemStatusFilter = GemStatus::NoFilter; + GemSelected m_gemSelectedFilter = GemSelected::NoFilter; + GemActive m_gemActiveFilter = GemActive::NoFilter; GemInfo::GemOrigins m_gemOriginFilter = {}; GemInfo::Platforms m_platformFilter = {}; GemInfo::Types m_typeFilter = {}; diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.cpp index 3e524d8ec8..88216398db 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.cpp @@ -11,10 +11,12 @@ namespace O3DE::ProjectManager { GemRepoInfo::GemRepoInfo( - const QString& name, const QString& creator, const QString& summary, const QDateTime& lastUpdated, bool isEnabled = true) + const QString& name, + const QString& creator, + const QDateTime& lastUpdated, + bool isEnabled = true) : m_name(name) , m_creator(creator) - , m_summary(summary) , m_lastUpdated(lastUpdated) , m_isEnabled(isEnabled) { diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.h index 6f4f828951..14c76bd0c2 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.h @@ -19,19 +19,25 @@ namespace O3DE::ProjectManager { public: GemRepoInfo() = default; - GemRepoInfo(const QString& name, const QString& creator, const QString& summary, const QDateTime& lastUpdated, bool isEnabled); + GemRepoInfo( + const QString& name, + const QString& creator, + const QDateTime& lastUpdated, + bool isEnabled); bool IsValid() const; bool operator<(const GemRepoInfo& gemRepoInfo) const; - QString m_path; + QString m_path = ""; QString m_name = "Unknown Gem Repo Name"; QString m_creator = "Unknown Creator"; bool m_isEnabled = false; //! Is the repo currently enabled for this engine? QString m_summary = "No summary provided."; - QString m_directoryLink; - QString m_repoLink; + QString m_additionalInfo = ""; + QString m_directoryLink = ""; + QString m_repoLink = ""; + QStringList m_includedGemPaths = {}; QDateTime m_lastUpdated; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInspector.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInspector.cpp new file mode 100644 index 0000000000..93f5890b94 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInspector.cpp @@ -0,0 +1,144 @@ +/* + * 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 +#include + +namespace O3DE::ProjectManager +{ + GemRepoInspector::GemRepoInspector(GemRepoModel* model, QWidget* parent) + : QScrollArea(parent) + , m_model(model) + { + setObjectName("gemRepoInspector"); + setWidgetResizable(true); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + + m_mainWidget = new QWidget(); + setWidget(m_mainWidget); + + m_mainLayout = new QVBoxLayout(); + m_mainLayout->setMargin(15); + m_mainLayout->setAlignment(Qt::AlignTop); + m_mainWidget->setLayout(m_mainLayout); + + InitMainWidget(); + + connect(m_model->GetSelectionModel(), &QItemSelectionModel::selectionChanged, this, &GemRepoInspector::OnSelectionChanged); + Update({}); + } + + void GemRepoInspector::OnSelectionChanged(const QItemSelection& selected, [[maybe_unused]] const QItemSelection& deselected) + { + const QModelIndexList selectedIndices = selected.indexes(); + if (selectedIndices.empty()) + { + Update({}); + return; + } + + Update(selectedIndices[0]); + } + + void GemRepoInspector::Update(const QModelIndex& modelIndex) + { + if (!modelIndex.isValid()) + { + m_mainWidget->hide(); + } + + // Repo name and url link + m_nameLabel->setText(m_model->GetName(modelIndex)); + m_repoLinkLabel->setText(m_model->GetRepoLink(modelIndex)); + m_repoLinkLabel->SetUrl(m_model->GetRepoLink(modelIndex)); + + // Repo summary + m_summaryLabel->setText(m_model->GetSummary(modelIndex)); + m_summaryLabel->adjustSize(); + + // Additional information + if (m_model->HasAdditionalInfo(modelIndex)) + { + m_addInfoTitleLabel->show(); + m_addInfoTextLabel->show(); + + m_addInfoSpacer->changeSize(0, 20, QSizePolicy::Fixed, QSizePolicy::Fixed); + + m_addInfoTextLabel->setText(m_model->GetAdditionalInfo(modelIndex)); + } + else + { + m_addInfoTitleLabel->hide(); + m_addInfoTextLabel->hide(); + + m_addInfoSpacer->changeSize(0, 0, QSizePolicy::Fixed, QSizePolicy::Fixed); + } + + // Included Gems + m_includedGems->Update(tr("Included Gems"), "", m_model->GetIncludedGemNames(modelIndex)); + + m_mainWidget->adjustSize(); + m_mainWidget->show(); + } + + void GemRepoInspector::InitMainWidget() + { + // Repo name and url link + m_nameLabel = new QLabel(); + m_nameLabel->setObjectName("gemRepoInspectorNameLabel"); + m_mainLayout->addWidget(m_nameLabel); + + m_repoLinkLabel = new LinkLabel(tr("Repo Url"), QUrl(""), 12, this); + m_mainLayout->addWidget(m_repoLinkLabel); + m_mainLayout->addSpacing(5); + + // Repo summary + m_summaryLabel = new QLabel(); + m_summaryLabel->setObjectName("gemRepoInspectorBodyLabel"); + m_summaryLabel->setWordWrap(true); + m_summaryLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + m_summaryLabel->setOpenExternalLinks(true); + m_mainLayout->addWidget(m_summaryLabel); + m_mainLayout->addSpacing(20); + + // Separating line + QFrame* hLine = new QFrame(); + hLine->setFrameShape(QFrame::HLine); + hLine->setObjectName("horizontalSeparatingLine"); + m_mainLayout->addWidget(hLine); + m_mainLayout->addSpacing(10); + + // Additional information + m_addInfoTitleLabel = new QLabel(); + m_addInfoTitleLabel->setObjectName("gemRepoInspectorAddInfoTitleLabel"); + m_addInfoTitleLabel->setText(tr("Additional Information")); + m_mainLayout->addWidget(m_addInfoTitleLabel); + + m_addInfoTextLabel = new QLabel(); + m_addInfoTextLabel->setObjectName("gemRepoInspectorBodyLabel"); + m_addInfoTextLabel->setWordWrap(true); + m_addInfoTextLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + m_addInfoTextLabel->setOpenExternalLinks(true); + m_mainLayout->addWidget(m_addInfoTextLabel); + + // Conditional spacing for additional info section + m_addInfoSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding); + m_mainLayout->addSpacerItem(m_addInfoSpacer); + + // Included Gems + m_includedGems = new GemsSubWidget(); + m_mainLayout->addWidget(m_includedGems); + m_mainLayout->addSpacing(20); + } +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInspector.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInspector.h new file mode 100644 index 0000000000..a14472e6a6 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInspector.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#include +#include + +#include +#include +#include +#include +#endif + +QT_FORWARD_DECLARE_CLASS(QVBoxLayout) +QT_FORWARD_DECLARE_CLASS(QLabel) + +namespace O3DE::ProjectManager +{ + class GemRepoInspector : public QScrollArea + { + Q_OBJECT // AUTOMOC + + public : explicit GemRepoInspector(GemRepoModel* model, QWidget* parent = nullptr); + ~GemRepoInspector() = default; + + void Update(const QModelIndex& modelIndex); + + private slots: + void OnSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); + + private: + void InitMainWidget(); + + GemRepoModel* m_model = nullptr; + QWidget* m_mainWidget = nullptr; + QVBoxLayout* m_mainLayout = nullptr; + + // General info section + QLabel* m_nameLabel = nullptr; + LinkLabel* m_repoLinkLabel = nullptr; + QLabel* m_summaryLabel = nullptr; + + // Additional information + QLabel* m_addInfoTitleLabel = nullptr; + QLabel* m_addInfoTextLabel = nullptr; + QSpacerItem* m_addInfoSpacer = nullptr; + + // Included Gems + GemsSubWidget* m_includedGems = nullptr; + }; +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.cpp index 519d52cb35..54d5b337e5 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.cpp @@ -11,13 +11,14 @@ namespace O3DE::ProjectManager { - GemRepoListView::GemRepoListView(QAbstractItemModel* model, QWidget* parent) + GemRepoListView::GemRepoListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent) : QListView(parent) { setObjectName("gemRepoListView"); setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); setModel(model); + setSelectionModel(selectionModel); setItemDelegate(new GemRepoItemDelegate(model, this)); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.h index 0fd5d5c180..b71b49f390 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.h @@ -10,6 +10,7 @@ #if !defined(Q_MOC_RUN) #include +#include #endif QT_FORWARD_DECLARE_CLASS(QAbstractItemModel) @@ -22,7 +23,7 @@ namespace O3DE::ProjectManager Q_OBJECT // AUTOMOC public: - explicit GemRepoListView(QAbstractItemModel* model, QWidget* parent = nullptr); + explicit GemRepoListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent = nullptr); ~GemRepoListView() = default; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.cpp index 7a42c135e9..61ac6dc8a3 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.cpp @@ -7,8 +7,10 @@ */ #include +#include #include +#include namespace O3DE::ProjectManager { @@ -16,6 +18,7 @@ namespace O3DE::ProjectManager : QStandardItemModel(parent) { m_selectionModel = new QItemSelectionModel(this, parent); + m_gemModel = new GemModel(this); } QItemSelectionModel* GemRepoModel::GetSelectionModel() const @@ -37,8 +40,17 @@ namespace O3DE::ProjectManager item->setData(gemRepoInfo.m_repoLink, RoleRepoLink); item->setData(gemRepoInfo.m_lastUpdated, RoleLastUpdated); item->setData(gemRepoInfo.m_path, RolePath); + item->setData(gemRepoInfo.m_additionalInfo, RoleAdditionalInfo); + item->setData(gemRepoInfo.m_includedGemPaths, RoleIncludedGems); appendRow(item); + + QVector includedGemInfos = GetIncludedGemInfos(item->index()); + + for (const GemInfo& gemInfo : includedGemInfos) + { + m_gemModel->AddGem(gemInfo); + } } void GemRepoModel::Clear() @@ -61,6 +73,11 @@ namespace O3DE::ProjectManager return modelIndex.data(RoleSummary).toString(); } + QString GemRepoModel::GetAdditionalInfo(const QModelIndex& modelIndex) + { + return modelIndex.data(RoleAdditionalInfo).toString(); + } + QString GemRepoModel::GetDirectoryLink(const QModelIndex& modelIndex) { return modelIndex.data(RoleDirectoryLink).toString(); @@ -81,6 +98,45 @@ namespace O3DE::ProjectManager return modelIndex.data(RolePath).toString(); } + QStringList GemRepoModel::GetIncludedGemPaths(const QModelIndex& modelIndex) + { + return modelIndex.data(RoleIncludedGems).toStringList(); + } + + QStringList GemRepoModel::GetIncludedGemNames(const QModelIndex& modelIndex) + { + QStringList gemNames; + QVector gemInfos = GetIncludedGemInfos(modelIndex); + + for (const GemInfo& gemInfo : gemInfos) + { + gemNames.append(gemInfo.m_displayName); + } + + return gemNames; + } + + QVector GemRepoModel::GetIncludedGemInfos(const QModelIndex& modelIndex) + { + QVector allGemInfos; + QStringList repoGemPaths = GetIncludedGemPaths(modelIndex); + + for (const QString& gemPath : repoGemPaths) + { + AZ::Outcome gemInfoResult = PythonBindingsInterface::Get()->GetGemInfo(gemPath); + if (gemInfoResult.IsSuccess()) + { + allGemInfos.append(gemInfoResult.GetValue()); + } + else + { + QMessageBox::critical(nullptr, tr("Gem Not Found"), tr("Cannot find info for gem %1.").arg(gemPath)); + } + } + + return allGemInfos; + } + bool GemRepoModel::IsEnabled(const QModelIndex& modelIndex) { return modelIndex.data(RoleIsEnabled).toBool(); @@ -91,4 +147,9 @@ namespace O3DE::ProjectManager model.setData(modelIndex, isEnabled, RoleIsEnabled); } + bool GemRepoModel::HasAdditionalInfo(const QModelIndex& modelIndex) + { + return !modelIndex.data(RoleAdditionalInfo).toString().isEmpty(); + } + } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.h index 2f1537d339..ad139bc12b 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.h @@ -11,6 +11,7 @@ #if !defined(Q_MOC_RUN) #include #include +#include #endif QT_FORWARD_DECLARE_CLASS(QItemSelectionModel) @@ -32,13 +33,19 @@ namespace O3DE::ProjectManager static QString GetName(const QModelIndex& modelIndex); static QString GetCreator(const QModelIndex& modelIndex); static QString GetSummary(const QModelIndex& modelIndex); + static QString GetAdditionalInfo(const QModelIndex& modelIndex); static QString GetDirectoryLink(const QModelIndex& modelIndex); static QString GetRepoLink(const QModelIndex& modelIndex); static QDateTime GetLastUpdated(const QModelIndex& modelIndex); static QString GetPath(const QModelIndex& modelIndex); + static QStringList GetIncludedGemPaths(const QModelIndex& modelIndex); + static QStringList GetIncludedGemNames(const QModelIndex& modelIndex); + static QVector GetIncludedGemInfos(const QModelIndex& modelIndex); + static bool IsEnabled(const QModelIndex& modelIndex); static void SetEnabled(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isEnabled); + static bool HasAdditionalInfo(const QModelIndex& modelIndex); private: enum UserRole @@ -50,9 +57,13 @@ namespace O3DE::ProjectManager RoleDirectoryLink, RoleRepoLink, RoleLastUpdated, - RolePath + RolePath, + RoleAdditionalInfo, + RoleIncludedGems, }; QItemSelectionModel* m_selectionModel = nullptr; + + GemModel* m_gemModel = nullptr; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index 82de53a0d0..c0b17904f8 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -40,10 +41,6 @@ namespace O3DE::ProjectManager hLayout->addSpacing(60); - m_gemRepoInspector = new QFrame(this); - m_gemRepoInspector->setObjectName(tr("gemRepoInspector")); - m_gemRepoInspector->setFixedWidth(240); - QVBoxLayout* middleVLayout = new QVBoxLayout(); middleVLayout->setMargin(0); middleVLayout->setSpacing(0); @@ -99,10 +96,13 @@ namespace O3DE::ProjectManager m_gemRepoHeaderTable->horizontalHeader()->setStyleSheet("QHeaderView::section { background-color:transparent; color:white; font-size:12px; text-align:left; border-style:none; }"); middleVLayout->addWidget(m_gemRepoHeaderTable); - m_gemRepoListView = new GemRepoListView(m_gemRepoModel, this); + m_gemRepoListView = new GemRepoListView(m_gemRepoModel, m_gemRepoModel->GetSelectionModel(), this); middleVLayout->addWidget(m_gemRepoListView); hLayout->addLayout(middleVLayout); + + m_gemRepoInspector = new GemRepoInspector(m_gemRepoModel, this); + m_gemRepoInspector->setFixedWidth(240); hLayout->addWidget(m_gemRepoInspector); Reinit(); @@ -134,7 +134,7 @@ namespace O3DE::ProjectManager } else { - QMessageBox::critical(this, tr("Operation failed"), QString("Cannot retrieve gem repos for engine.\n\nError:\n%2").arg(allGemRepoInfosResult.GetError().c_str())); + QMessageBox::critical(this, tr("Operation failed"), tr("Cannot retrieve gem repos for engine.\n\nError:\n%2").arg(allGemRepoInfosResult.GetError().c_str())); } } diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h index b5316db84f..f7d943fc2a 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h @@ -19,6 +19,7 @@ QT_FORWARD_DECLARE_CLASS(QTableWidget) namespace O3DE::ProjectManager { + QT_FORWARD_DECLARE_CLASS(GemRepoInspector) QT_FORWARD_DECLARE_CLASS(GemRepoListView) QT_FORWARD_DECLARE_CLASS(GemRepoModel) @@ -40,7 +41,7 @@ namespace O3DE::ProjectManager QTableWidget* m_gemRepoHeaderTable = nullptr; QHeaderView* m_gemRepoListHeader = nullptr; GemRepoListView* m_gemRepoListView = nullptr; - QFrame* m_gemRepoInspector = nullptr; + GemRepoInspector* m_gemRepoInspector = nullptr; GemRepoModel* m_gemRepoModel = nullptr; QLabel* m_lastAllUpdateLabel; diff --git a/Code/Tools/ProjectManager/Source/GemsSubWidget.cpp b/Code/Tools/ProjectManager/Source/GemsSubWidget.cpp new file mode 100644 index 0000000000..eb24008eb1 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemsSubWidget.cpp @@ -0,0 +1,45 @@ +/* + * 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 + +namespace O3DE::ProjectManager +{ + GemsSubWidget::GemsSubWidget(QWidget* parent) + : QWidget(parent) + { + m_layout = new QVBoxLayout(); + m_layout->setAlignment(Qt::AlignTop); + m_layout->setMargin(0); + setLayout(m_layout); + + m_titleLabel = new QLabel(); + m_titleLabel->setObjectName("gemSubWidgetTitleLabel"); + m_layout->addWidget(m_titleLabel); + + m_textLabel = new QLabel(); + m_textLabel->setObjectName("gemSubWidgetTextLabel"); + m_textLabel->setWordWrap(true); + m_layout->addWidget(m_textLabel); + + m_tagWidget = new TagContainerWidget(); + m_layout->addWidget(m_tagWidget); + } + + void GemsSubWidget::Update(const QString& title, const QString& text, const QStringList& gemNames) + { + m_titleLabel->setText(title); + m_textLabel->setText(text); + m_tagWidget->Update(gemNames); + } +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemsSubWidget.h b/Code/Tools/ProjectManager/Source/GemsSubWidget.h new file mode 100644 index 0000000000..1b10ec8861 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemsSubWidget.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#include +#endif + +QT_FORWARD_DECLARE_CLASS(QVBoxLayout) +QT_FORWARD_DECLARE_CLASS(QLabel) + +namespace O3DE::ProjectManager +{ + // Title, description and tag widget container used for the depending and conflicting gems + class GemsSubWidget + : public QWidget + { + public: + GemsSubWidget(QWidget* parent = nullptr); + void Update(const QString& title, const QString& text, const QStringList& gemNames); + + private: + QLabel* m_titleLabel = nullptr; + QLabel* m_textLabel = nullptr; + QVBoxLayout* m_layout = nullptr; + TagContainerWidget* m_tagWidget = nullptr; + }; +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/LinkWidget.cpp b/Code/Tools/ProjectManager/Source/LinkWidget.cpp index ccee7e8ec6..9c8c78ed37 100644 --- a/Code/Tools/ProjectManager/Source/LinkWidget.cpp +++ b/Code/Tools/ProjectManager/Source/LinkWidget.cpp @@ -14,9 +14,10 @@ namespace O3DE::ProjectManager { - LinkLabel::LinkLabel(const QString& text, const QUrl& url, QWidget* parent) + LinkLabel::LinkLabel(const QString& text, const QUrl& url, int fontSize, QWidget* parent) : QLabel(text, parent) , m_url(url) + , m_fontSize(fontSize) { SetDefaultStyle(); } @@ -33,7 +34,7 @@ namespace O3DE::ProjectManager void LinkLabel::enterEvent([[maybe_unused]] QEvent* event) { - setStyleSheet("font-size: 10px; color: #94D2FF; text-decoration: underline;"); + setStyleSheet(QString("font-size: %1px; color: #94D2FF; text-decoration: underline;").arg(m_fontSize)); } void LinkLabel::leaveEvent([[maybe_unused]] QEvent* event) @@ -48,6 +49,6 @@ namespace O3DE::ProjectManager void LinkLabel::SetDefaultStyle() { - setStyleSheet("font-size: 10px; color: #94D2FF;"); + setStyleSheet(QString("font-size: %1px; color: #94D2FF;").arg(m_fontSize)); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/LinkWidget.h b/Code/Tools/ProjectManager/Source/LinkWidget.h index a50007cf1f..eb0b9bb528 100644 --- a/Code/Tools/ProjectManager/Source/LinkWidget.h +++ b/Code/Tools/ProjectManager/Source/LinkWidget.h @@ -25,7 +25,7 @@ namespace O3DE::ProjectManager Q_OBJECT // AUTOMOC public: - LinkLabel(const QString& text = {}, const QUrl& url = {}, QWidget* parent = nullptr); + LinkLabel(const QString& text = {}, const QUrl& url = {}, int fontSize = 10, QWidget* parent = nullptr); void SetUrl(const QUrl& url); @@ -40,5 +40,6 @@ namespace O3DE::ProjectManager private: QUrl m_url; + int m_fontSize; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index c92ad53cd4..284ed9dcec 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -675,6 +675,14 @@ namespace O3DE::ProjectManager } } + if (data.contains("dependencies")) + { + for (auto dependency : data["dependencies"]) + { + gemInfo.m_dependencies.push_back(Py_To_String(dependency)); + } + } + QString gemType = Py_To_String_Optional(data, "type", ""); if (gemType == "Asset") { @@ -946,8 +954,16 @@ namespace O3DE::ProjectManager return AZ::Failure(result.GetError().c_str()); } #else - gemRepos.push_back(GemRepoInfo("JohnCreates", "John Smith", "", QDateTime(QDate(2021, 8, 31), QTime(11, 57)), true)); - gemRepos.push_back(GemRepoInfo("JanesGems", "Jane Doe", "", QDateTime(QDate(2021, 9, 10), QTime(18, 23)), false)); + GemRepoInfo mockJohnRepo("JohnCreates", "John Smith", QDateTime(QDate(2021, 8, 31), QTime(11, 57)), true); + mockJohnRepo.m_summary = "John's Summary. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sollicitudin dapibus urna"; + mockJohnRepo.m_repoLink = "https://github.com/o3de/o3de"; + mockJohnRepo.m_additionalInfo = "John's additional info. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sollicitu."; + gemRepos.push_back(mockJohnRepo); + + GemRepoInfo mockJaneRepo("JanesGems", "Jane Doe", QDateTime(QDate(2021, 9, 10), QTime(18, 23)), false); + mockJaneRepo.m_summary = "Jane's Summary."; + mockJaneRepo.m_repoLink = "https://github.com/o3de/o3de.org"; + gemRepos.push_back(mockJaneRepo); #endif // MOCK_GEM_REPO_INFO std::sort(gemRepos.begin(), gemRepos.end()); diff --git a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h index 9fd3002f93..ccf217d25b 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h +++ b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h @@ -56,8 +56,9 @@ namespace O3DE::ProjectManager // Gems /** - * Get info about a Gem - * @param projectPath the absolute path to the Gem + * Get info about a Gem. + * @param path The absolute path to the Gem + * @param projectPath (Optional) The absolute path to the Gem project * @return an outcome with GemInfo on success */ virtual AZ::Outcome GetGemInfo(const QString& path, const QString& projectPath = {}) = 0; diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake index 7a336972e0..f71ae290e7 100644 --- a/Code/Tools/ProjectManager/project_manager_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_files.cmake @@ -27,6 +27,8 @@ set(FILES Source/FormFolderBrowseEditWidget.cpp Source/FormImageBrowseEditWidget.h Source/FormImageBrowseEditWidget.cpp + Source/GemsSubWidget.h + Source/GemsSubWidget.cpp Source/PathValidator.h Source/PathValidator.cpp Source/ProjectManagerWindow.h @@ -104,6 +106,8 @@ set(FILES Source/GemRepo/GemRepoScreen.cpp Source/GemRepo/GemRepoInfo.h Source/GemRepo/GemRepoInfo.cpp + Source/GemRepo/GemRepoInspector.h + Source/GemRepo/GemRepoInspector.cpp Source/GemRepo/GemRepoItemDelegate.h Source/GemRepo/GemRepoItemDelegate.cpp Source/GemRepo/GemRepoListView.h diff --git a/Code/Tools/ProjectManager/project_manager_tests_files.cmake b/Code/Tools/ProjectManager/project_manager_tests_files.cmake index 2b22ced910..2bfe343038 100644 --- a/Code/Tools/ProjectManager/project_manager_tests_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_tests_files.cmake @@ -11,6 +11,7 @@ set(FILES Resources/ProjectManager.qss tests/ApplicationTests.cpp tests/PythonBindingsTests.cpp + tests/GemCatalogTests.cpp tests/main.cpp tests/UtilsTests.cpp ) diff --git a/Code/Tools/ProjectManager/tests/GemCatalogTests.cpp b/Code/Tools/ProjectManager/tests/GemCatalogTests.cpp new file mode 100644 index 0000000000..f5c6d5196a --- /dev/null +++ b/Code/Tools/ProjectManager/tests/GemCatalogTests.cpp @@ -0,0 +1,64 @@ +/* + * 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 O3DE::ProjectManager +{ + class GemCatalogTests + : public ::UnitTest::ScopedAllocatorSetupFixture + { + public: + + GemCatalogTests() = default; + }; + + TEST_F(GemCatalogTests, GemCatalog_Displays_But_Does_Not_Add_Dependencies) + { + GemModel* gemModel = new GemModel(); + + // given 3 gems a,b,c where a depends on b which depends on c + GemInfo gemA, gemB, gemC; + QModelIndex indexA, indexB, indexC; + gemA.m_name = "a"; + gemB.m_name = "b"; + gemC.m_name = "c"; + + gemA.m_dependencies = QStringList({ "b" }); + gemB.m_dependencies = QStringList({ "c" }); + + gemModel->AddGem(gemA); + indexA = gemModel->FindIndexByNameString(gemA.m_name); + + gemModel->AddGem(gemB); + indexB = gemModel->FindIndexByNameString(gemB.m_name); + + gemModel->AddGem(gemC); + indexC = gemModel->FindIndexByNameString(gemC.m_name); + + gemModel->UpdateGemDependencies(); + + EXPECT_FALSE(GemModel::IsAdded(indexA)); + EXPECT_FALSE(GemModel::IsAddedDependency(indexB) || GemModel::IsAddedDependency(indexC)); + + // when a is added + GemModel::SetIsAdded(*gemModel, indexA, true); + + // expect b and c are now dependencies of an added gem but not themselves added + // cmake will handle dependencies + EXPECT_TRUE(GemModel::IsAddedDependency(indexB) && GemModel::IsAddedDependency(indexC)); + EXPECT_TRUE(!GemModel::IsAdded(indexB) && !GemModel::IsAdded(indexC)); + + QVector gemsToAdd = gemModel->GatherGemsToBeAdded(); + EXPECT_TRUE(gemsToAdd.size() == 1); + EXPECT_EQ(GemModel::GetName(gemsToAdd.at(0)), gemA.m_name); + } +} diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuilderUtility.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuilderUtility.cpp index eb91d9e866..e9ac18a432 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuilderUtility.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuilderUtility.cpp @@ -37,6 +37,7 @@ #include #include "ShaderPlatformInterfaceRequest.h" +#include "ShaderBuilder_Traits_Platform.h" #include "AtomShaderConfig.h" #include "SrgLayoutUtility.h" @@ -456,8 +457,9 @@ namespace AZ const uint32_t rhiUniqueIndex, const AZStd::string& platformIdentifier, const AZStd::string& shaderJsonPath, const uint32_t supervariantIndex, RPI::ShaderAssetSubId shaderAssetSubId) { - // platform id from identifier - AzFramework::PlatformId platformId = AzFramework::PlatformId::PC; + // Define a fallback platform ID based on the current host platform + AzFramework::PlatformId platformId = AZ_TRAIT_ATOM_FALLBACK_ASSET_HOST_PLATFORM; + if (platformIdentifier == "pc") { platformId = AzFramework::PlatformId::PC; @@ -478,6 +480,10 @@ namespace AZ { platformId = AzFramework::PlatformId::IOS; } + else if (platformIdentifier == "server") + { + platformId = AzFramework::PlatformId::SERVER; + } uint32_t assetSubId = RPI::ShaderAsset::MakeProductAssetSubId(rhiUniqueIndex, supervariantIndex, aznumeric_cast(shaderAssetSubId)); auto assetIdOutcome = RPI::AssetUtils::MakeAssetId(shaderJsonPath, assetSubId); diff --git a/Gems/Atom/Asset/Shader/Code/Source/Platform/Android/ShaderBuilder_Traits_Android.h b/Gems/Atom/Asset/Shader/Code/Source/Platform/Android/ShaderBuilder_Traits_Android.h index f8d93059f3..86afcd201c 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Platform/Android/ShaderBuilder_Traits_Android.h +++ b/Gems/Atom/Asset/Shader/Code/Source/Platform/Android/ShaderBuilder_Traits_Android.h @@ -8,3 +8,4 @@ #pragma once #define AZ_TRAIT_ATOM_SHADERBUILDER_AZSLC UNUSED_TRAIT +#define AZ_TRAIT_ATOM_FALLBACK_ASSET_HOST_PLATFORM UNUSED_TRAIT diff --git a/Gems/Atom/Asset/Shader/Code/Source/Platform/Linux/ShaderBuilder_Traits_Linux.h b/Gems/Atom/Asset/Shader/Code/Source/Platform/Linux/ShaderBuilder_Traits_Linux.h index efa5a3e9ea..54a0a1fd5d 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Platform/Linux/ShaderBuilder_Traits_Linux.h +++ b/Gems/Atom/Asset/Shader/Code/Source/Platform/Linux/ShaderBuilder_Traits_Linux.h @@ -8,4 +8,4 @@ #pragma once #define AZ_TRAIT_ATOM_SHADERBUILDER_AZSLC "azslc" - +#define AZ_TRAIT_ATOM_FALLBACK_ASSET_HOST_PLATFORM AzFramework::PlatformId::LINUX_ID diff --git a/Gems/Atom/Asset/Shader/Code/Source/Platform/Mac/ShaderBuilder_Traits_Mac.h b/Gems/Atom/Asset/Shader/Code/Source/Platform/Mac/ShaderBuilder_Traits_Mac.h index d47967a559..7b93324711 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Platform/Mac/ShaderBuilder_Traits_Mac.h +++ b/Gems/Atom/Asset/Shader/Code/Source/Platform/Mac/ShaderBuilder_Traits_Mac.h @@ -8,3 +8,4 @@ #pragma once #define AZ_TRAIT_ATOM_SHADERBUILDER_AZSLC "azslc" +#define AZ_TRAIT_ATOM_FALLBACK_ASSET_HOST_PLATFORM AzFramework::PlatformId::MAC_ID diff --git a/Gems/Atom/Asset/Shader/Code/Source/Platform/Windows/ShaderBuilder_Traits_Windows.h b/Gems/Atom/Asset/Shader/Code/Source/Platform/Windows/ShaderBuilder_Traits_Windows.h index 3645897fa2..d6dd19fbfb 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Platform/Windows/ShaderBuilder_Traits_Windows.h +++ b/Gems/Atom/Asset/Shader/Code/Source/Platform/Windows/ShaderBuilder_Traits_Windows.h @@ -8,3 +8,4 @@ #pragma once #define AZ_TRAIT_ATOM_SHADERBUILDER_AZSLC "azslc.exe" +#define AZ_TRAIT_ATOM_FALLBACK_ASSET_HOST_PLATFORM AzFramework::PlatformId::PC diff --git a/Gems/Atom/Asset/Shader/Code/Source/Platform/iOS/ShaderBuilder_Traits_iOS.h b/Gems/Atom/Asset/Shader/Code/Source/Platform/iOS/ShaderBuilder_Traits_iOS.h index f8d93059f3..86afcd201c 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Platform/iOS/ShaderBuilder_Traits_iOS.h +++ b/Gems/Atom/Asset/Shader/Code/Source/Platform/iOS/ShaderBuilder_Traits_iOS.h @@ -8,3 +8,4 @@ #pragma once #define AZ_TRAIT_ATOM_SHADERBUILDER_AZSLC UNUSED_TRAIT +#define AZ_TRAIT_ATOM_FALLBACK_ASSET_HOST_PLATFORM UNUSED_TRAIT diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp index 2057c596e5..29db7d6673 100644 --- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp @@ -9,8 +9,6 @@ #include "AuxGeomDrawQueue.h" -#include - #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomFeatureProcessor.cpp index ee6d3ba4a3..a4720ad131 100644 --- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomFeatureProcessor.cpp @@ -12,7 +12,6 @@ #include "DynamicPrimitiveProcessor.h" #include "FixedShapeProcessor.h" -#include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/DynamicPrimitiveProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/DynamicPrimitiveProcessor.cpp index 9af6493413..ae9e55ac8d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/DynamicPrimitiveProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/DynamicPrimitiveProcessor.cpp @@ -9,7 +9,6 @@ #include "DynamicPrimitiveProcessor.h" #include "AuxGeomDrawProcessorShared.h" -#include #include #include #include @@ -21,6 +20,8 @@ #include #include +#include + namespace AZ { namespace Render diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.cpp index 8b5e439ca0..c2ee397b4c 100644 --- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.cpp @@ -12,7 +12,6 @@ #include #include -#include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/CapsuleLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/CapsuleLightFeatureProcessor.cpp index 849c930afd..bbea462ac8 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/CapsuleLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/CapsuleLightFeatureProcessor.cpp @@ -16,7 +16,6 @@ #include #include -#include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp index 702818dcd9..42cca0e57c 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp @@ -12,7 +12,6 @@ #include #include -#include #include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp index ca2c038e46..26e1757a5a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp @@ -16,7 +16,6 @@ #include -#include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp index bfb0b1252b..d3b5646e0b 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp @@ -16,7 +16,6 @@ #include #include -#include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PolygonLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PolygonLightFeatureProcessor.cpp index 9dbf01ae26..f3c05eeeec 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PolygonLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PolygonLightFeatureProcessor.cpp @@ -16,7 +16,6 @@ #include -#include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/QuadLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/QuadLightFeatureProcessor.cpp index aadc8c2020..787e150646 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/QuadLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/QuadLightFeatureProcessor.cpp @@ -16,7 +16,6 @@ #include -#include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimplePointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimplePointLightFeatureProcessor.cpp index f49a5e94fc..bc13d3d508 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimplePointLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimplePointLightFeatureProcessor.cpp @@ -16,7 +16,6 @@ #include #include -#include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimpleSpotLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimpleSpotLightFeatureProcessor.cpp index 277b5026d7..49b7f7d12c 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimpleSpotLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimpleSpotLightFeatureProcessor.cpp @@ -16,7 +16,6 @@ #include #include -#include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.cpp index 4ff718b5ad..f00c902a73 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.cpp @@ -10,7 +10,6 @@ #include -#include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp index 1a68317532..0ff8d2c165 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp @@ -15,7 +15,6 @@ #include -#include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/ImageBasedLights/ImageBasedLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/ImageBasedLights/ImageBasedLightFeatureProcessor.cpp index 9cdad34f17..6a2eda8f22 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ImageBasedLights/ImageBasedLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ImageBasedLights/ImageBasedLightFeatureProcessor.cpp @@ -11,8 +11,6 @@ #include #include -#include - #include namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index bd0d12106b..82568126df 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -8,7 +8,6 @@ #include -#include #include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.cpp index d5b3ebd63b..a9d8d5105f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.cpp @@ -8,8 +8,6 @@ #include -#include - #include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp index a795d88212..eef0c51e95 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp @@ -16,8 +16,6 @@ #include -#include - #include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp index 920326e081..a476b5b839 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp @@ -8,7 +8,6 @@ #include "ProfilingCaptureSystemComponent.h" -#include #include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.h b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.h index 1846767139..9f8a8a90c6 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.h +++ b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.h @@ -12,7 +12,6 @@ #include #include -#include namespace AZ { diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp index a17ecaf1aa..042e934eb0 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -105,14 +104,31 @@ namespace AZ m_meshes[objectIndex].m_subMeshes = subMeshes; } + Mesh& mesh = m_meshes[objectIndex]; + + // search for an existing BLAS instance entry for this mesh using the assetId + BlasInstanceMap::iterator itMeshBlasInstance = m_blasInstanceMap.find(assetId); + if (itMeshBlasInstance == m_blasInstanceMap.end()) + { + // make a new BLAS map entry for this mesh + MeshBlasInstance meshBlasInstance; + meshBlasInstance.m_count = 1; + meshBlasInstance.m_subMeshes.reserve(mesh.m_subMeshes.size()); + itMeshBlasInstance = m_blasInstanceMap.insert({ assetId, meshBlasInstance }).first; + } + else + { + itMeshBlasInstance->second.m_count++; + } + // create the BLAS buffers for each sub-mesh, or re-use existing BLAS objects if they were already created. // Note: all sub-meshes must either create new BLAS objects or re-use existing ones, otherwise it's an error (it's the same model in both cases) // Note: the buffer is just reserved here, the BLAS is built in the RayTracingAccelerationStructurePass - Mesh& mesh = m_meshes[objectIndex]; bool blasInstanceFound = false; - - for (auto& subMesh : mesh.m_subMeshes) + for (uint32_t subMeshIndex = 0; subMeshIndex < mesh.m_subMeshes.size(); ++subMeshIndex) { + SubMesh& subMesh = mesh.m_subMeshes[subMeshIndex]; + RHI::RayTracingBlasDescriptor blasDescriptor; blasDescriptor.Build() ->Geometry() @@ -121,13 +137,11 @@ namespace AZ ->IndexBuffer(subMesh.m_indexBufferView) ; - // search for an existing BLAS object for this model - RayTracingBlasMap::iterator itBlas = m_blasMap.find(assetId); - if (itBlas != m_blasMap.end()) + // determine if we have an existing BLAS object for this subMesh + if (itMeshBlasInstance->second.m_subMeshes.size() >= subMeshIndex + 1) { // re-use existing BLAS - subMesh.m_blas = itBlas->second.m_blas; - itBlas->second.m_count++; + subMesh.m_blas = itMeshBlasInstance->second.m_subMeshes[subMeshIndex].m_blas; // keep track of the fact that we re-used a BLAS blasInstanceFound = true; @@ -143,8 +157,7 @@ namespace AZ subMesh.m_blas->CreateBuffers(*device, &blasDescriptor, *m_bufferPools); // store the BLAS in the side list - RayTracingBlasInstance blasInstance = { subMesh.m_blas, 1 }; - m_blasMap.insert({ assetId, blasInstance }); + itMeshBlasInstance->second.m_subMeshes.push_back({ subMesh.m_blas }); } } @@ -182,16 +195,16 @@ namespace AZ m_meshes.erase(itMesh); m_revision++; - // decrement the count from the BLAS instance, and check to see if we can remove it - RayTracingBlasMap::iterator itBlas = m_blasMap.find(itMesh->second.m_assetId); - if (itBlas != m_blasMap.end()) + // decrement the count from the BLAS instances, and check to see if we can remove them + BlasInstanceMap::iterator itBlas = m_blasInstanceMap.find(itMesh->second.m_assetId); + if (itBlas != m_blasInstanceMap.end()) { itBlas->second.m_count--; if (itBlas->second.m_count == 0) { - m_blasMap.erase(itBlas); + m_blasInstanceMap.erase(itBlas); } - } + } } m_meshInfoBufferNeedsUpdate = true; diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h index be75f0fac9..52bb67f547 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h @@ -268,14 +268,19 @@ namespace AZ bool m_materialInfoBufferNeedsUpdate = false; // side list for looking up existing BLAS objects so they can be re-used when the same mesh is added multiple times - struct RayTracingBlasInstance + struct SubMeshBlasInstance { RHI::Ptr m_blas; - uint32_t m_count = 0; }; - using RayTracingBlasMap = AZStd::unordered_map; - RayTracingBlasMap m_blasMap; + struct MeshBlasInstance + { + uint32_t m_count = 0; + AZStd::vector m_subMeshes; + }; + + using BlasInstanceMap = AZStd::unordered_map; + BlasInstanceMap m_blasInstanceMap; }; } } diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp index 9fecbc19fc..52d089ae0d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp index 8fb971f8f5..c0202c7c74 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp index 500eadf110..e0209702dc 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp @@ -22,7 +22,6 @@ #include #include -#include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/SkyBox/SkyBoxFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/SkyBox/SkyBoxFeatureProcessor.cpp index d4fa3f52be..ca8775a073 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkyBox/SkyBoxFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkyBox/SkyBoxFeatureProcessor.cpp @@ -12,7 +12,6 @@ #include -#include #include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/TransformService/TransformServiceFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/TransformService/TransformServiceFeatureProcessor.cpp index 6f9c0dc73a..141acbd744 100644 --- a/Gems/Atom/Feature/Common/Code/Source/TransformService/TransformServiceFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/TransformService/TransformServiceFeatureProcessor.cpp @@ -8,7 +8,6 @@ #include -#include #include #include diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/MemorySubAllocator.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/MemorySubAllocator.h index bdeb252174..3e464a6974 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/MemorySubAllocator.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/MemorySubAllocator.h @@ -7,7 +7,6 @@ */ #pragma once -#include #include #include #include diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/ObjectCollector.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/ObjectCollector.h index 988416326e..7558442ad1 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/ObjectCollector.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/ObjectCollector.h @@ -7,8 +7,9 @@ */ #pragma once -#include #include + +#include #include #include #include diff --git a/Gems/Atom/RHI/Code/Source/RHI/BufferPool.cpp b/Gems/Atom/RHI/Code/Source/RHI/BufferPool.cpp index 5d06d02668..94b0b57c37 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/BufferPool.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/BufferPool.cpp @@ -7,7 +7,6 @@ */ #include -#include #include #include diff --git a/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp b/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp index 0983d4db22..b50c36d3f9 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp @@ -7,9 +7,10 @@ */ #include -#include #include +#include + namespace AZ { namespace RHI diff --git a/Gems/Atom/RHI/Code/Source/RHI/Device.cpp b/Gems/Atom/RHI/Code/Source/RHI/Device.cpp index 9453ff79ee..2f4ca297a1 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/Device.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/Device.cpp @@ -6,7 +6,6 @@ * */ -#include #include #include diff --git a/Gems/Atom/RHI/Code/Source/RHI/Fence.cpp b/Gems/Atom/RHI/Code/Source/RHI/Fence.cpp index ca0493a52c..d030ff8d2b 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/Fence.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/Fence.cpp @@ -8,6 +8,8 @@ #include +#include + namespace AZ { namespace RHI diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp index b85fa88f34..9f3d21a2f1 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameGraphCompiler.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameGraphCompiler.cpp index 5c5691d975..d06ec002e4 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/FrameGraphCompiler.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/FrameGraphCompiler.cpp @@ -6,7 +6,6 @@ * */ -#include #include #include #include diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp index 429081cd2c..6888531b67 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp @@ -6,7 +6,6 @@ * */ #include -#include #include #include #include diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp index 90218709fa..df887379fe 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp @@ -6,7 +6,6 @@ * */ -#include #include #include #include diff --git a/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp b/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp index 868580f0c7..0c06887dd6 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp @@ -6,9 +6,10 @@ * */ -#include #include #include + +#include #include #include diff --git a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp index 69f7002435..ad3ab119ef 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp @@ -6,12 +6,12 @@ * */ -#include #include #include #include #include +#include #include #include diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListPool.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListPool.cpp index 94262064da..20021e71ba 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListPool.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListPool.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include namespace AZ diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp index eee137026d..9bf25d8bc6 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp @@ -5,7 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#include + #include #include #include diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.cpp index 816b904e16..635c66f1cd 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include namespace AZ diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp index 722d535cb1..4ff7d581a4 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueueContext.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueueContext.cpp index fb11700e04..e4c651c2b1 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueueContext.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueueContext.cpp @@ -7,7 +7,6 @@ */ #include -#include #include #include #include diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/FrameGraphCompiler.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/FrameGraphCompiler.cpp index a347ed9b12..9ee000e166 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/FrameGraphCompiler.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/FrameGraphCompiler.cpp @@ -5,7 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#include + #include #include #include diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/Scope.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/Scope.cpp index 7e4d510dfa..c680684efd 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/Scope.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/Scope.cpp @@ -5,7 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#include + #include #include #include diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.cpp index 567f89b6e0..d05e1a00a3 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.cpp @@ -6,10 +6,10 @@ * */ +#include #include #include #include -#include #include #include #include diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueueContext.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueueContext.cpp index c0d34e2bf9..ec7311cd6e 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueueContext.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueueContext.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphCompiler.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphCompiler.cpp index 2a30e36e04..e153ad6645 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphCompiler.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphCompiler.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index fbfabe4f2a..348f0aa57a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -14,8 +14,6 @@ #include #include -#include - #include #include #include diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/GpuQuerySystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/GpuQuerySystem.cpp index 8077038ea7..0143c8ee2d 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/GpuQuerySystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/GpuQuerySystem.cpp @@ -7,7 +7,6 @@ */ #include -#include #include #include #include diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Image/ImageSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Image/ImageSystem.cpp index 71e2eaa2f5..f201e8414c 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Image/ImageSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Image/ImageSystem.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #include diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp index 34d72338dc..f4f51f97b7 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -19,7 +19,6 @@ #include -#include #include #include diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index 778548f14c..a7ecf089c0 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -6,8 +6,6 @@ * */ -#include - #include #include #include diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAssetCreator.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAssetCreator.cpp index bb80a1b8d2..feeeff36cf 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAssetCreator.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAssetCreator.cpp @@ -57,7 +57,7 @@ namespace AZ // Only allocate buffer if initial data is not empty if (initialData != nullptr && initialDataSize > 0) { - bufferAsset->m_buffer.resize(descriptor.m_byteCount); + bufferAsset->m_buffer.resize_no_construct(descriptor.m_byteCount); memcpy(bufferAsset->m_buffer.data(), initialData, initialDataSize); } diff --git a/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Behaviors/ActorGroupBehavior.cpp b/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Behaviors/ActorGroupBehavior.cpp index f1f1361585..d89e41f1a6 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Behaviors/ActorGroupBehavior.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Behaviors/ActorGroupBehavior.cpp @@ -176,19 +176,10 @@ namespace EMotionFX return AZ::SceneAPI::Events::ProcessingResult::Ignored; } - const bool hasBoneData = AZ::SceneAPI::Utilities::DoesSceneGraphContainDataLike(scene, true); + // Skip adding the actor group if it doesn't contain any skin and blendshape data. const bool hasSkinData = AZ::SceneAPI::Utilities::DoesSceneGraphContainDataLike(scene, true); - const bool hasBlendShapeData = - AZ::SceneAPI::Utilities::DoesSceneGraphContainDataLike(scene, true); - // Skip adding the actor group if it doesn't contain any bone, skin and blendshape data. - if (!hasBoneData && !hasSkinData && !hasBlendShapeData) - { - return AZ::SceneAPI::Events::ProcessingResult::Ignored; - } - - const bool hasAnimationData = AZ::SceneAPI::Utilities::DoesSceneGraphContainDataLike(scene, true); - // Skip adding the actor group if it contains animation data but doesn't contain any skin or blendshape data. - if (hasAnimationData && !hasSkinData && !hasBlendShapeData) + const bool hasBlendShapeData = AZ::SceneAPI::Utilities::DoesSceneGraphContainDataLike(scene, true); + if (!hasSkinData && !hasBlendShapeData) { return AZ::SceneAPI::Events::ProcessingResult::Ignored; } @@ -197,7 +188,7 @@ namespace EMotionFX AZStd::shared_ptr group = AZStd::make_shared(); // This is a group that's generated automatically so may not be saved to disk but would need to be recreated - // in the same way again. To guarantee the same uuid, generate a stable one instead. + // in the same way again. To guarantee the same uuid, generate a stable one instead. group->OverrideId(AZ::SceneAPI::DataTypes::Utilities::CreateStableUuid(scene, Group::ActorGroup::TYPEINFO_Uuid())); EBUS_EVENT(AZ::SceneAPI::Events::ManifestMetaInfoBus, InitializeObject, scene, *group); diff --git a/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Groups/ActorGroup.cpp b/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Groups/ActorGroup.cpp index 9e080fca3b..90c25c575f 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Groups/ActorGroup.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Groups/ActorGroup.cpp @@ -108,7 +108,7 @@ namespace EMotionFX serializeContext->Class()->Version(3, IActorGroupVersionConverter); - serializeContext->Class()->Version(6, ActorVersionConverter) + serializeContext->Class()->Version(7, ActorVersionConverter) ->Field("name", &ActorGroup::m_name) ->Field("selectedRootBone", &ActorGroup::m_selectedRootBone) ->Field("id", &ActorGroup::m_id) diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/NodeGroup.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/NodeGroup.cpp index 74e59150e0..8eae2fb127 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/NodeGroup.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/NodeGroup.cpp @@ -6,12 +6,10 @@ * */ -// include the required headers #include "NodeGroup.h" #include "ActorInstance.h" #include - namespace EMotionFX { AZ_CLASS_ALLOCATOR_IMPL(NodeGroup, NodeAllocator, 0) @@ -104,10 +102,7 @@ namespace EMotionFX // remove a given node by its node number void NodeGroup::RemoveNodeByNodeIndex(uint16 nodeIndex) { - if (const auto found = AZStd::find(begin(m_nodes), end(m_nodes), nodeIndex); found) - { - m_nodes.erase(found); - } + m_nodes.erase(AZStd::remove(m_nodes.begin(), m_nodes.end(), nodeIndex), m_nodes.end()); } diff --git a/Gems/EditorPythonBindings/Code/Source/PythonProxyBus.cpp b/Gems/EditorPythonBindings/Code/Source/PythonProxyBus.cpp index 38b29bcdf2..f9f9580c1a 100644 --- a/Gems/EditorPythonBindings/Code/Source/PythonProxyBus.cpp +++ b/Gems/EditorPythonBindings/Code/Source/PythonProxyBus.cpp @@ -195,7 +195,7 @@ namespace EditorPythonBindings if (!m_handler) { - AZ_Error("python", false, "No EBus connection deteced; missing call or failed call to connect()?"); + AZ_Error("python", false, "No EBus connection detected; missing call or failed call to connect()?"); return false; } diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkCharacterComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkCharacterComponent.h index 478c925299..9af22b1fdf 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkCharacterComponent.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkCharacterComponent.h @@ -19,6 +19,22 @@ namespace Physics namespace Multiplayer { + //! NetworkCharacterRequests + //! ComponentBus handled by NetworkCharacterComponentController. + //! Bus was created for exposing controller methods to script; C++ users should access the controller directly. + class NetworkCharacterRequests : public AZ::ComponentBus + { + public: + //! TryMoveWithVelocity + //! Will move this character entity kinematically through physical world while also ensuring the network stays in-sync. + //! Velocity will be applied over delta-time to determine the movement amount. + //! Returns this entity's world-space position after the move. + virtual AZ::Vector3 TryMoveWithVelocity(const AZ::Vector3& velocity, float deltaTime) = 0; + }; + + typedef AZ::EBus NetworkCharacterRequestBus; + + //! NetworkCharacterComponent //! Provides multiplayer support for game-play player characters. class NetworkCharacterComponent @@ -39,6 +55,12 @@ namespace Multiplayer incompatible.push_back(AZ_CRC_CE("NetworkRigidBodyService")); } + static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) + { + NetworkCharacterComponentBase::GetRequiredServices(required); + required.push_back(AZ_CRC_CE("PhysXCharacterControllerService")); + } + // AZ::Component void OnInit() override {} void OnActivate(Multiplayer::EntityIsMigrating entityIsMigrating) override; @@ -65,18 +87,22 @@ namespace Multiplayer //! Class provides the ability to move characters in physical space while keeping the network in-sync. class NetworkCharacterComponentController : public NetworkCharacterComponentControllerBase + , private NetworkCharacterRequestBus::Handler { public: + AZ_RTTI(NetworkCharacterComponentController, "{C91851A2-8B95-4484-9F97-BFF9D1F528A0}") + static void Reflect(AZ::ReflectContext* context); NetworkCharacterComponentController(NetworkCharacterComponent& parent); // NetworkCharacterComponentControllerBase void OnActivate(Multiplayer::EntityIsMigrating entityIsMigrating) override; void OnDeactivate(Multiplayer::EntityIsMigrating entityIsMigrating) override; + // NetworkCharacterRequestBus::Handler //! TryMoveWithVelocity //! Will move this character entity kinematically through physical world while also ensuring the network stays in-sync. //! Velocity will be applied over delta-time to determine the movement amount. //! Returns this entity's world-space position after the move. - AZ::Vector3 TryMoveWithVelocity(const AZ::Vector3& velocity, float deltaTime); + AZ::Vector3 TryMoveWithVelocity(const AZ::Vector3& velocity, float deltaTime) override; }; } diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkRigidBodyComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkRigidBodyComponent.h index 19379fc959..cec73b1b71 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkRigidBodyComponent.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkRigidBodyComponent.h @@ -1,5 +1,6 @@ /* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. * * SPDX-License-Identifier: Apache-2.0 OR MIT * diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja index 5bf0a4823f..02ab556cea 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja @@ -170,12 +170,20 @@ AZ::Event<{{ Property.attrib['Type'] }}> {% set PropertyName = UpperFirst(Property.attrib['Name']) %} {{ ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }} {% if IsOverride %} +{% if paramDefines|count > 0 %} void Handle{{ PropertyName }}(AzNetworking::IConnection* invokingConnection, {{ ', '.join(paramDefines) }}) override {} +{% else %} +void Handle{{ PropertyName }}(AzNetworking::IConnection* invokingConnection) override {} +{% endif %} {% else %} //! {{ PropertyName }} Handler //! {{ Property.attrib['Description'] }} //! HandleOn {{ HandleOn }} +{% if paramDefines|count > 0 %} virtual void Handle{{ PropertyName }}([[maybe_unused]] AzNetworking::IConnection* invokingConnection, [[maybe_unused]] {{ ', [[maybe_unused]] '.join(paramDefines) }}) {} +{% else %} +virtual void Handle{{ PropertyName }}([[maybe_unused]] AzNetworking::IConnection* invokingConnection) {} +{% endif %} {% endif %} {% endmacro %} {# diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index eb4b81ea96..cf62f6f901 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -909,6 +909,7 @@ enum class NetworkProperties controller->Set{{ UpperFirst(Property.attrib['Name']) }}({{ LowerFirst(Property.attrib['Name']) }}); {% endif %} }) +{% if Property.attrib['GenerateEventBindings']|booleanTrue %} {% if Property.attrib['Container'] == 'Vector' or Property.attrib['Container'] == 'Array' -%} ->Method("GetOn{{ UpperFirst(Property.attrib['Name']) }}ChangedEvent", [](AZ::EntityId id) -> AZ::Event* {% else %} @@ -936,6 +937,7 @@ enum class NetworkProperties {% else %} ->Attribute(AZ::Script::Attributes::AzEventDescription, AZ::BehaviorAzEventDescription{ "On {{ UpperFirst(Property.attrib['Name']) }} Changed Event", {"New {{ Property.attrib['Type'] }}"} }) {% endif %} +{% endif %} {% endif %} {% endcall %} @@ -1518,7 +1520,7 @@ namespace {{ Component.attrib['Namespace'] }} {{ ReflectRpcEventDescs(Component, ComponentName, 'Authority', 'Autonomous')|indent(4) -}} {{ ReflectRpcEventDescs(Component, ComponentName, 'Authority', 'Client')|indent(4) }} - behaviorContext->Class<{{ ComponentName }}>("{{ ComponentName }}") + behaviorContext->Class<{{ ComponentBaseName }}>("{{ ComponentBaseName }}") ->Attribute(AZ::Script::Attributes::Module, "{{ LowerFirst(Component.attrib['Namespace']) }}") ->Attribute(AZ::Script::Attributes::Category, "{{ UpperFirst(Component.attrib['Namespace']) }}") diff --git a/Gems/Multiplayer/Code/Source/Components/NetworkCharacterComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetworkCharacterComponent.cpp index b14fc8761f..33eb26653a 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetworkCharacterComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetworkCharacterComponent.cpp @@ -83,7 +83,7 @@ namespace Multiplayer return physx::PxQueryHitType::eNONE; } - void NetworkCharacterComponent::NetworkCharacterComponent::Reflect(AZ::ReflectContext* context) + void NetworkCharacterComponent::Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) @@ -92,6 +92,7 @@ namespace Multiplayer ->Version(1); } NetworkCharacterComponentBase::Reflect(context); + NetworkCharacterComponentController::Reflect(context); } NetworkCharacterComponent::NetworkCharacterComponent() @@ -161,6 +162,18 @@ namespace Multiplayer return state.touchedActor != nullptr || (state.collisionFlags & physx::PxControllerCollisionFlag::eCOLLISION_DOWN) != 0; } + void NetworkCharacterComponentController::Reflect(AZ::ReflectContext* context) + { + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->EBus("NetworkCharacterRequestBus") + ->Event("TryMoveWithVelocity", &NetworkCharacterRequestBus::Events::TryMoveWithVelocity, {{ { "Velocity" }, { "DeltaTime" } }}); + + behaviorContext->Class("NetworkCharacterComponentController") + ->RequestBus("NetworkCharacterRequestBus"); + } + } + NetworkCharacterComponentController::NetworkCharacterComponentController(NetworkCharacterComponent& parent) : NetworkCharacterComponentControllerBase(parent) { @@ -169,12 +182,12 @@ namespace Multiplayer void NetworkCharacterComponentController::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) { - ; + NetworkCharacterRequestBus::Handler::BusConnect(GetEntity()->GetId()); } void NetworkCharacterComponentController::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) { - ; + NetworkCharacterRequestBus::Handler::BusDisconnect(GetEntity()->GetId()); } AZ::Vector3 NetworkCharacterComponentController::TryMoveWithVelocity(const AZ::Vector3& velocity, [[maybe_unused]] float deltaTime) diff --git a/Gems/Multiplayer/Code/Source/Components/NetworkRigidBodyComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetworkRigidBodyComponent.cpp index bcf855d834..725ebc024c 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetworkRigidBodyComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetworkRigidBodyComponent.cpp @@ -1,5 +1,6 @@ /* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. * * SPDX-License-Identifier: Apache-2.0 OR MIT * diff --git a/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.cpp b/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.cpp index d33c3274c2..5d677c6101 100644 --- a/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.cpp @@ -24,6 +24,13 @@ namespace Multiplayer } } + void NetworkSpawnableHolderComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) + { + // TransformService isn't strictly required in this component (Identity transform will be used by default) + // However we need to make sure if there's a component providing TransformService it is activated first. + dependent.push_back(AZ_CRC_CE("TransformService")); + } + NetworkSpawnableHolderComponent::NetworkSpawnableHolderComponent() { } @@ -38,11 +45,9 @@ namespace Multiplayer { AZ::Transform rootEntityTransform = AZ::Transform::CreateIdentity(); - AzFramework::TransformComponent* rootEntityTransformComponent = - GetEntity()->FindComponent(); - if (rootEntityTransformComponent) + if(auto* transformInterface = GetEntity()->GetTransform()) { - rootEntityTransform = rootEntityTransformComponent->GetWorldTM(); + rootEntityTransform = transformInterface->GetWorldTM(); } INetworkEntityManager* networkEntityManager = GetNetworkEntityManager(); diff --git a/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.h b/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.h index 3836212c48..c95a1a5442 100644 --- a/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.h +++ b/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.h @@ -22,11 +22,12 @@ namespace Multiplayer public: AZ_COMPONENT(NetworkSpawnableHolderComponent, "{B0E3ADEE-FCB4-4A32-8D4F-6920F1CB08E4}"); - static void Reflect(AZ::ReflectContext* context); - NetworkSpawnableHolderComponent();; ~NetworkSpawnableHolderComponent() override = default; + static void Reflect(AZ::ReflectContext* context); + static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); + //! AZ::Component overrides. //! @{ void Activate() override; diff --git a/Gems/Multiplayer/Code/Tests/ClientHierarchyTests.cpp b/Gems/Multiplayer/Code/Tests/ClientHierarchyTests.cpp index 38ea451c85..316f85c214 100644 --- a/Gems/Multiplayer/Code/Tests/ClientHierarchyTests.cpp +++ b/Gems/Multiplayer/Code/Tests/ClientHierarchyTests.cpp @@ -307,7 +307,7 @@ namespace Multiplayer class ClientDeepHierarchyTests : public ClientSimpleHierarchyTests { public: - static const NetEntityId ChildOfChildNetEntityId = NetEntityId{ 3 }; + const NetEntityId ChildOfChildNetEntityId = NetEntityId{ 3 }; void SetUp() override { diff --git a/Gems/Multiplayer/Code/Tests/ServerHierarchyTests.cpp b/Gems/Multiplayer/Code/Tests/ServerHierarchyTests.cpp index 70859909b3..385a4b83ae 100644 --- a/Gems/Multiplayer/Code/Tests/ServerHierarchyTests.cpp +++ b/Gems/Multiplayer/Code/Tests/ServerHierarchyTests.cpp @@ -414,12 +414,12 @@ namespace Multiplayer class ServerBranchedHierarchyTests : public HierarchyTests { public: - static const NetEntityId RootNetEntityId = NetEntityId{ 1 }; - static const NetEntityId ChildNetEntityId = NetEntityId{ 2 }; - static const NetEntityId ChildOfChildNetEntityId = NetEntityId{ 3 }; - static const NetEntityId Child2NetEntityId = NetEntityId{ 4 }; - static const NetEntityId ChildOfChild2NetEntityId = NetEntityId{ 5 }; - static const NetEntityId Child2OfChild2NetEntityId = NetEntityId{ 6 }; + const NetEntityId RootNetEntityId = NetEntityId{ 1 }; + const NetEntityId ChildNetEntityId = NetEntityId{ 2 }; + const NetEntityId ChildOfChildNetEntityId = NetEntityId{ 3 }; + const NetEntityId Child2NetEntityId = NetEntityId{ 4 }; + const NetEntityId ChildOfChild2NetEntityId = NetEntityId{ 5 }; + const NetEntityId Child2OfChild2NetEntityId = NetEntityId{ 6 }; void SetUp() override { @@ -610,9 +610,9 @@ namespace Multiplayer class ServerHierarchyOfHierarchyTests : public ServerDeepHierarchyTests { public: - static const NetEntityId Root2NetEntityId = NetEntityId{ 4 }; - static const NetEntityId Child2NetEntityId = NetEntityId{ 5 }; - static const NetEntityId ChildOfChild2NetEntityId = NetEntityId{ 6 }; + const NetEntityId Root2NetEntityId = NetEntityId{ 4 }; + const NetEntityId Child2NetEntityId = NetEntityId{ 5 }; + const NetEntityId ChildOfChild2NetEntityId = NetEntityId{ 6 }; void SetUp() override { @@ -1132,9 +1132,9 @@ namespace Multiplayer class ServerHierarchyWithThreeRoots : public ServerHierarchyOfHierarchyTests { public: - static const NetEntityId Root3NetEntityId = NetEntityId{ 7 }; - static const NetEntityId Child3NetEntityId = NetEntityId{ 8 }; - static const NetEntityId ChildOfChild3NetEntityId = NetEntityId{ 9 }; + const NetEntityId Root3NetEntityId = NetEntityId{ 7 }; + const NetEntityId Child3NetEntityId = NetEntityId{ 8 }; + const NetEntityId ChildOfChild3NetEntityId = NetEntityId{ 9 }; void SetUp() override { diff --git a/cmake/Platform/Mac/PAL_mac.cmake b/cmake/Platform/Mac/PAL_mac.cmake index 065b35d69c..561ce86570 100644 --- a/cmake/Platform/Mac/PAL_mac.cmake +++ b/cmake/Platform/Mac/PAL_mac.cmake @@ -37,6 +37,10 @@ endif() # Set the default asset type for deployment set(LY_ASSET_DEPLOY_ASSET_TYPE "mac" CACHE STRING "Set the asset type for deployment.") +# Set the deployment target for MacOS +set(LY_MAC_DEPLOYMENT_TARGET "11.0" CACHE STRING "Mac Deployment Target") +set(CMAKE_OSX_DEPLOYMENT_TARGET ${LY_MAC_DEPLOYMENT_TARGET}) + # Set the python cmd tool ly_set(LY_PYTHON_CMD ${CMAKE_CURRENT_SOURCE_DIR}/python/python.sh) diff --git a/cmake/Platform/iOS/Toolchain_ios.cmake b/cmake/Platform/iOS/Toolchain_ios.cmake index 49f0b23461..719c492ebb 100644 --- a/cmake/Platform/iOS/Toolchain_ios.cmake +++ b/cmake/Platform/iOS/Toolchain_ios.cmake @@ -13,7 +13,7 @@ set(CMAKE_OSX_ARCHITECTURES arm64) set(LY_IOS_CODE_SIGNING_IDENTITY "iPhone Developer" CACHE STRING "iPhone Developer") -set(LY_IOS_DEPLOYMENT_TARGET "13.0" CACHE STRING "iOS Deployment Target") +set(LY_IOS_DEPLOYMENT_TARGET "14.0" CACHE STRING "iOS Deployment Target") set(LY_IOS_DEVELOPMENT_TEAM "CF9TGN983S" CACHE STRING "The development team ID")