diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIBus.h index f7119f3e14..b639686269 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIBus.h @@ -36,6 +36,10 @@ namespace AzToolsFramework //! the entity type. virtual AZStd::vector FindComponentTypeIdsByEntityType(const AZStd::vector& componentTypeNames, EntityType entityType) = 0; + //! Return a list of type ids for components that match the required services filter, + //! and don't conflict with any of the incompatible services filter + virtual AZStd::vector FindComponentTypeIdsByService(const AZStd::vector& serviceFilter, const AZStd::vector& incompatibleServiceFilter) = 0; + //! Finds the component names from their type ids virtual AZStd::vector FindComponentTypeNames(const AZ::ComponentTypeList& componentTypeIds) = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.cpp index 30a7c603bd..2cca3804ea 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -75,6 +76,7 @@ namespace AzToolsFramework serializeContext->Class(); serializeContext->RegisterGenericType>(); + serializeContext->RegisterGenericType>(); } if (auto behaviorContext = azrtti_cast(context)) @@ -99,6 +101,7 @@ namespace AzToolsFramework ->Attribute(AZ::Script::Attributes::Module, "editor") ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) ->Event("FindComponentTypeIdsByEntityType", &EditorComponentAPIRequests::FindComponentTypeIdsByEntityType) + ->Event("FindComponentTypeIdsByService", &EditorComponentAPIRequests::FindComponentTypeIdsByService) ->Event("FindComponentTypeNames", &EditorComponentAPIRequests::FindComponentTypeNames) ->Event("BuildComponentTypeNameListByEntityType", &EditorComponentAPIRequests::BuildComponentTypeNameListByEntityType) ->Event("AddComponentsOfType", &EditorComponentAPIRequests::AddComponentsOfType) @@ -216,6 +219,33 @@ namespace AzToolsFramework return foundTypeIds; } + AZStd::vector EditorComponentAPIComponent::FindComponentTypeIdsByService(const AZStd::vector& serviceFilter, const AZStd::vector& incompatibleServiceFilter) + { + AZStd::vector foundTypeIds; + + m_serializeContext->EnumerateDerived( + [&foundTypeIds, serviceFilter, incompatibleServiceFilter](const AZ::SerializeContext::ClassData* componentClass, const AZ::Uuid& knownType) -> bool + { + AZ_UNUSED(knownType); + + if (componentClass->m_editData) + { + // If none of the required services are offered by this component, or the component + // can not be added by the user, skip to the next component + if (!OffersRequiredServices(componentClass, serviceFilter, incompatibleServiceFilter)) + { + return true; + } + + foundTypeIds.push_back(componentClass->m_typeId); + } + + return true; + }); + + return foundTypeIds; + } + AZStd::vector EditorComponentAPIComponent::FindComponentTypeNames(const AZ::ComponentTypeList& componentTypeIds) { AZStd::vector foundTypeNames; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.h index 2b74ea98c5..3e7eede77f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.h @@ -35,6 +35,7 @@ namespace AzToolsFramework // EditorComponentAPIBus ... AZStd::vector FindComponentTypeIdsByEntityType(const AZStd::vector& componentTypeNames, EditorComponentAPIRequests::EntityType entityType) override; + AZStd::vector FindComponentTypeIdsByService(const AZStd::vector& serviceFilter, const AZStd::vector& incompatibleServiceFilter) override; AZStd::vector FindComponentTypeNames(const AZ::ComponentTypeList& componentTypeIds) override; AZStd::vector BuildComponentTypeNameListByEntityType(EditorComponentAPIRequests::EntityType entityType) override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp index 8d40162f52..28d6e2bc08 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp @@ -271,6 +271,68 @@ namespace AzToolsFramework return editorComponentBaseComponent; } + bool OffersRequiredServices( + const AZ::SerializeContext::ClassData* componentClass, + const AZStd::vector& serviceFilter, + const AZStd::vector& incompatibleServiceFilter + ) + { + AZ_Assert(componentClass, "Component class must not be null"); + + if (!componentClass) + { + return false; + } + + AZ::ComponentDescriptor* componentDescriptor = nullptr; + AZ::ComponentDescriptorBus::EventResult( + componentDescriptor, componentClass->m_typeId, &AZ::ComponentDescriptor::GetDescriptor); + if (!componentDescriptor) + { + return false; + } + + // If no services are provided, this function returns true + if (serviceFilter.empty()) + { + return true; + } + + AZ::ComponentDescriptor::DependencyArrayType providedServices; + componentDescriptor->GetProvidedServices(providedServices, nullptr); + + //reject this component if it does not offer any of the required services + if (AZStd::find_first_of( + providedServices.begin(), + providedServices.end(), + serviceFilter.begin(), + serviceFilter.end()) == providedServices.end()) + { + return false; + } + + //reject this component if it does offer any of the incompatible services + if (AZStd::find_first_of( + providedServices.begin(), + providedServices.end(), + incompatibleServiceFilter.begin(), + incompatibleServiceFilter.end()) != providedServices.end()) + { + return false; + } + + return true; + } + + bool OffersRequiredServices( + const AZ::SerializeContext::ClassData* componentClass, + const AZStd::vector& serviceFilter + ) + { + const AZStd::vector incompatibleServices; + return OffersRequiredServices(componentClass, serviceFilter, incompatibleServices); + } + bool ShouldInspectorShowComponent(const AZ::Component* component) { if (!component) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.h index 73acb2deb0..c2d693c553 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.h @@ -105,6 +105,16 @@ namespace AzToolsFramework AZ::ComponentDescriptor* GetComponentDescriptor(const AZ::Component* component); Components::EditorComponentDescriptor* GetEditorComponentDescriptor(const AZ::Component* component); Components::EditorComponentBase* GetEditorComponent(AZ::Component* component); + // Returns true if the given component provides at least one of the services specified or no services are provided + bool OffersRequiredServices( + const AZ::SerializeContext::ClassData* componentClass, + const AZStd::vector& serviceFilter, + const AZStd::vector& incompatibleServiceFilter + ); + bool OffersRequiredServices( + const AZ::SerializeContext::ClassData* componentClass, + const AZStd::vector& serviceFilter + ); /// Return true if the editor should show this component to users, /// false if the component should be hidden from users. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/ComponentPalette/ComponentPaletteUtil.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/ComponentPalette/ComponentPaletteUtil.cpp index 6f3727bdb4..b6f5b41b65 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/ComponentPalette/ComponentPaletteUtil.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/ComponentPalette/ComponentPaletteUtil.cpp @@ -12,6 +12,7 @@ #include #include #include +#include AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") // 4251: 'QLayoutItem::align': class 'QFlags' needs to have dll-interface to be used by clients of class 'QLayoutItem' #include AZ_POP_DISABLE_WARNING @@ -20,67 +21,6 @@ namespace AzToolsFramework { namespace ComponentPaletteUtil { - bool OffersRequiredServices( - const AZ::SerializeContext::ClassData* componentClass, - const AZStd::vector& serviceFilter, - const AZStd::vector& incompatibleServiceFilter - ) - { - AZ_Assert(componentClass, "Component class must not be null"); - - if (!componentClass) - { - return false; - } - - AZ::ComponentDescriptor* componentDescriptor = nullptr; - EBUS_EVENT_ID_RESULT(componentDescriptor, componentClass->m_typeId, AZ::ComponentDescriptorBus, GetDescriptor); - if (!componentDescriptor) - { - return false; - } - - // If no services are provided, this function returns true - if (serviceFilter.empty()) - { - return true; - } - - AZ::ComponentDescriptor::DependencyArrayType providedServices; - componentDescriptor->GetProvidedServices(providedServices, nullptr); - - //reject this component if it does not offer any of the required services - if (AZStd::find_first_of( - providedServices.begin(), - providedServices.end(), - serviceFilter.begin(), - serviceFilter.end()) == providedServices.end()) - { - return false; - } - - //reject this component if it does offer any of the incompatible services - if (AZStd::find_first_of( - providedServices.begin(), - providedServices.end(), - incompatibleServiceFilter.begin(), - incompatibleServiceFilter.end()) != providedServices.end()) - { - return false; - } - - return true; - } - - bool OffersRequiredServices( - const AZ::SerializeContext::ClassData* componentClass, - const AZStd::vector& serviceFilter - ) - { - const AZStd::vector incompatibleServices; - return OffersRequiredServices(componentClass, serviceFilter, incompatibleServices); - } - bool IsAddableByUser(const AZ::SerializeContext::ClassData* componentClass) { AZ_Assert(componentClass, "component class must not be null"); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/ComponentPalette/ComponentPaletteUtil.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/ComponentPalette/ComponentPaletteUtil.hxx index 2000d72c5c..dffb893c59 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/ComponentPalette/ComponentPaletteUtil.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/ComponentPalette/ComponentPaletteUtil.hxx @@ -26,18 +26,6 @@ namespace AzToolsFramework using ComponentIconTable = AZStd::map; - // Returns true if the given component provides at least one of the services specified or no services are provided - bool OffersRequiredServices( - const AZ::SerializeContext::ClassData* componentClass, - const AZStd::vector& serviceFilter, - const AZStd::vector& incompatibleServiceFilter - ); - - bool OffersRequiredServices( - const AZ::SerializeContext::ClassData* componentClass, - const AZStd::vector& serviceFilter - ); - // Returns true if the given component is addable by the user bool IsAddableByUser(const AZ::SerializeContext::ClassData* componentClass); diff --git a/Code/Framework/AzToolsFramework/Tests/EntityInspectorTests.cpp b/Code/Framework/AzToolsFramework/Tests/EntityInspectorTests.cpp index 0fbc7eba98..d640a91eab 100644 --- a/Code/Framework/AzToolsFramework/Tests/EntityInspectorTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/EntityInspectorTests.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include // Inspector Test Includes @@ -313,17 +314,17 @@ namespace UnitTest AZ_TEST_ASSERT(testComponent1_ProvidedServices.size() == 1); const AZ::SerializeContext::ClassData* testComponent1_ClassData = context->FindClassData(testComponent1_typeId); - EXPECT_TRUE(AzToolsFramework::ComponentPaletteUtil::OffersRequiredServices(testComponent1_ClassData, testComponent1_ProvidedServices)); + EXPECT_TRUE(AzToolsFramework::OffersRequiredServices(testComponent1_ClassData, testComponent1_ProvidedServices)); // Verify that OffersRequiredServices returns when given services provided by a different component AZ::ComponentDescriptor::DependencyArrayType testComponent2_ProvidedServices; Inspector_TestComponent2::GetProvidedServices(testComponent2_ProvidedServices); AZ_TEST_ASSERT(testComponent2_ProvidedServices.size() == 1); AZ_TEST_ASSERT(testComponent1_ProvidedServices != testComponent2_ProvidedServices); - EXPECT_FALSE(AzToolsFramework::ComponentPaletteUtil::OffersRequiredServices(testComponent1_ClassData, testComponent2_ProvidedServices)); + EXPECT_FALSE(AzToolsFramework::OffersRequiredServices(testComponent1_ClassData, testComponent2_ProvidedServices)); // verify that OffersRequiredServices returns true when provided with an empty list of services - EXPECT_TRUE(AzToolsFramework::ComponentPaletteUtil::OffersRequiredServices(testComponent1_ClassData, AZ::ComponentDescriptor::DependencyArrayType())); + EXPECT_TRUE(AzToolsFramework::OffersRequiredServices(testComponent1_ClassData, AZ::ComponentDescriptor::DependencyArrayType())); ////////////////////////////////////////////////////////////////////////// // TEST IsAddableByUser()