diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityModel.cpp index 9caca69b34..ef6d0fe1f8 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityModel.cpp @@ -117,8 +117,6 @@ namespace AzToolsFramework { EditorEntityModel::EditorEntityModel() { - AzFramework::ApplicationRequests::Bus::BroadcastResult(m_isPrefabEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled); - EntityCompositionNotificationBus::Handler::BusConnect(); EditorOnlyEntityComponentNotificationBus::Handler::BusConnect(); EditorEntityRuntimeActivationChangeNotificationBus::Handler::BusConnect(); @@ -565,7 +563,7 @@ namespace AzToolsFramework { //retrieve or add an entity entry to the table //the entry must exist, even if not connected, so children and other data can be assigned - [[maybe_unused]] auto [it, inserted] = m_entityInfoTable.try_emplace(entityId, m_isPrefabEnabled); + [[maybe_unused]] auto [it, inserted] = m_entityInfoTable.try_emplace(entityId); auto& entityInfo = it->second; //the entity id defaults to invalid and must be set to match the requested id @@ -882,11 +880,6 @@ namespace AzToolsFramework } } - EditorEntityModel::EditorEntityModelEntry::EditorEntityModelEntry(bool isPrefabEnabled) - : m_isPrefabEnabled(isPrefabEnabled) - { - } - EditorEntityModel::EditorEntityModelEntry::~EditorEntityModelEntry() { Disconnect(); @@ -1213,29 +1206,15 @@ namespace AzToolsFramework auto childItr = m_childIndexCache.find(childId); if (childItr != m_childIndexCache.end()) { - if (m_isPrefabEnabled) - { - // Take the last entry and move it into the removed spot instead of deleting the entry and having to move all - // following entries one step down. - AZ::EntityId backEntity = m_children.back(); - m_children[childItr->second] = backEntity; - // Update cached index for the moved id to the new index. - m_childIndexCache[backEntity] = childItr->second; - // Now remove the deleted id from the children and cache. - m_childIndexCache.erase(childId); - m_children.erase(m_children.end() - 1); - } - else - { - m_children.erase(m_children.begin() + childItr->second); - - // rebuild index cache for faster lookup - m_childIndexCache.clear(); - for (auto childIdToCache : m_children) - { - m_childIndexCache[childIdToCache] = static_cast(m_childIndexCache.size()); - } - } + // Take the last entry and move it into the removed spot instead of deleting the entry and having to move all + // following entries one step down. + AZ::EntityId backEntity = m_children.back(); + m_children[childItr->second] = backEntity; + // Update cached index for the moved id to the new index. + m_childIndexCache[backEntity] = childItr->second; + // Now remove the deleted id from the children and cache. + m_childIndexCache.erase(childId); + m_children.erase(m_children.end() - 1); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityModel.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityModel.h index b6cceb85fe..72965b4017 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityModel.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityModel.h @@ -171,7 +171,6 @@ namespace AzToolsFramework , public PropertyEditorEntityChangeNotificationBus::Handler { public: - explicit EditorEntityModelEntry(bool isPrefabEnabled); ~EditorEntityModelEntry(); // Separately connect to EditorEntityInfoRequestBus and refresh Entity @@ -336,7 +335,6 @@ namespace AzToolsFramework bool m_visible = true; bool m_locked = false; bool m_connected = false; - bool m_isPrefabEnabled = false; AZStd::string m_name; AZStd::string m_sliceAssetName; AZStd::unordered_map m_childIndexCache; @@ -375,6 +373,5 @@ namespace AzToolsFramework AZ::EntityId m_postInstantiateBeforeEntity; AZ::EntityId m_postInstantiateSliceParent; bool m_gotInstantiateSliceDetails = false; - bool m_isPrefabEnabled = false; }; } diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp index c81db58c95..d1bd2a488e 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp @@ -78,7 +78,7 @@ namespace Benchmark } BENCHMARK_REGISTER_F(BM_PrefabUpdateInstances, UpdateInstances_SingeEntityInstances) ->RangeMultiplier(10) - ->Range(100, 1000) + ->Range(100, 10000) ->Unit(benchmark::kMillisecond) ->Complexity(); diff --git a/Code/Sandbox/Editor/MainWindow.cpp b/Code/Sandbox/Editor/MainWindow.cpp index 895df4214f..e9bfd96a1d 100644 --- a/Code/Sandbox/Editor/MainWindow.cpp +++ b/Code/Sandbox/Editor/MainWindow.cpp @@ -1327,7 +1327,7 @@ QToolButton* MainWindow::CreateDebugModeButton() QWidget* MainWindow::CreateSpacerRightWidget() { - QWidget* spacer = new QWidget(); + QWidget* spacer = new QWidget(this); spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); spacer->setVisible(true); return spacer; diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerListModel.cpp b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerListModel.cpp index cd423535f2..49d56f67df 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerListModel.cpp +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerListModel.cpp @@ -1473,13 +1473,14 @@ void OutlinerListModel::OnEntityInfoUpdatedRemoveChildBegin(AZ::EntityId parentI emit EnableSelectionUpdates(false); auto parentIndex = GetIndexFromEntity(parentId); auto childIndex = GetIndexFromEntity(childId); - beginRemoveRows(parentIndex, childIndex.row(), childIndex.row()); + beginResetModel(); } void OutlinerListModel::OnEntityInfoUpdatedRemoveChildEnd(AZ::EntityId parentId, AZ::EntityId childId) { (void)childId; AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); + endRemoveRows(); //must refresh partial lock/visibility of parents diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp new file mode 100644 index 0000000000..b11c7a7a2c --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp @@ -0,0 +1,25 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include "GemInfo.h" + +namespace O3DE::ProjectManager +{ + GemInfo::GemInfo(const QString& name, const QString& creator, const QString& summary, Platforms platforms, bool isAdded) + : m_name(name) + , m_creator(creator) + , m_summary(summary) + , m_platforms(platforms) + , m_isAdded(isAdded) + { + } +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h new file mode 100644 index 0000000000..e5aa9c41f7 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h @@ -0,0 +1,55 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#include +#include +#include +#endif + +namespace O3DE::ProjectManager +{ + class GemInfo + { + public: + enum Platform + { + Android = 0x0, + iOS = 0x1, + Linux = 0x2, + macOS = 0x3, + Windows = 0x4 + }; + Q_DECLARE_FLAGS(Platforms, Platform) + + GemInfo(const QString& name, const QString& creator, const QString& summary, Platforms platforms, bool isAdded); + + QString m_name; + QString m_displayName; + AZ::Uuid m_uuid; + QString m_creator; + bool m_isAdded = false; //! Is the gem currently added and enabled in the project? + QString m_summary; + Platforms m_platforms; + QStringList m_features; + QString m_version; + QString m_lastUpdatedDate; + QString m_documentationUrl; + QVector m_dependingGemUuids; + QVector m_conflictingGemUuids; + }; +} // namespace O3DE::ProjectManager + +Q_DECLARE_OPERATORS_FOR_FLAGS(O3DE::ProjectManager::GemInfo::Platforms) diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake index 333180ea78..a97ff692b7 100644 --- a/Code/Tools/ProjectManager/project_manager_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_files.cmake @@ -37,4 +37,6 @@ set(FILES Source/EngineSettings.h Source/EngineSettings.cpp Source/EngineSettings.ui + Source/GemCatalog/GemInfo.h + Source/GemCatalog/GemInfo.cpp ) diff --git a/Gems/AWSCore/Code/Include/Private/Configuration/AWSCoreConfiguration.h b/Gems/AWSCore/Code/Include/Private/Configuration/AWSCoreConfiguration.h index f3d474f053..bd30af3ce7 100644 --- a/Gems/AWSCore/Code/Include/Private/Configuration/AWSCoreConfiguration.h +++ b/Gems/AWSCore/Code/Include/Private/Configuration/AWSCoreConfiguration.h @@ -25,13 +25,24 @@ namespace AWSCore : AWSCoreInternalRequestBus::Handler { public: - static constexpr const char AWSCORE_CONFIGURATION_FILENAME[] = "awscoreconfiguration.setreg"; + static constexpr const char AWSCoreConfigurationName[] = "AWSCoreConfiguration"; + static constexpr const char AWSCoreConfigurationFileName[] = "awscoreconfiguration.setreg"; - static constexpr const char AWSCORE_RESOURCE_MAPPING_CONFIG_FOLDERNAME[] = "Config"; - static constexpr const char AWSCORE_RESOURCE_MAPPING_CONFIG_FILENAME_KEY[] = "/AWSCore/ResourceMappingConfigFileName"; + static constexpr const char AWSCoreResourceMappingConfigFolderName[] = "Config"; + static constexpr const char AWSCoreResourceMappingConfigFileNameKey[] = "/AWSCore/ResourceMappingConfigFileName"; + + static constexpr const char AWSCoreDefaultProfileName[] = "default"; + static constexpr const char AWSCoreProfileNameKey[] = "/AWSCore/ProfileName"; + + static constexpr const char ProjectSourceFolderNotFoundErrorMessage[] = + "Failed to get project source folder path."; + static constexpr const char ProfileNameNotFoundErrorMessage[] = + "Failed to get profile name, return default value instead."; + static constexpr const char ResourceMappingFileNameNotFoundErrorMessage[] = + "Failed to get resource mapping config file name, return empty value instead."; + static constexpr const char SettingsRegistryLoadFailureErrorMessage[] = + "Failed to load AWSCore settings registry file."; - static constexpr const char AWSCORE_DEFAULT_PROFILE_NAME[] = "default"; - static constexpr const char AWSCORE_PROFILENAME_KEY[] = "/AWSCore/ProfileName"; AWSCoreConfiguration(); ~AWSCoreConfiguration() = default; @@ -55,6 +66,9 @@ namespace AWSCore // Parse values from project .setreg file void ParseSettingsRegistryValues(); + // Reset settings registry data + void ResetSettingsRegistryData(); + AZStd::string m_sourceProjectFolder; AZ::SettingsRegistryImpl m_settingsRegistry; AZStd::string m_profileName; diff --git a/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingConstants.h b/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingConstants.h index 2ca203bb96..55360f1c76 100644 --- a/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingConstants.h +++ b/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingConstants.h @@ -14,20 +14,20 @@ namespace AWSCore { - static constexpr const char AWS_CHINA_REGION_PREFIX[] = "cn-"; + static constexpr const char AWSChinaRegionPrefix[] = "cn-"; - static constexpr const char AWS_FEATURE_GEM_RESTAPI_ID_KEYNAME_SUFFIX[] = ".RESTApiId"; - static constexpr const char AWS_FEATURE_GEM_RESTAPI_STAGE_KEYNAME_SUFFIX[] = ".RESTApiStage"; + static constexpr const char AWSFeatureGemRESTApiIdKeyNameSuffix[] = ".RESTApiId"; + static constexpr const char AWSFeatureGemRESTApiStageKeyNameSuffix[] = ".RESTApiStage"; - static constexpr const char RESOURCE_MAPPING_ACCOUNTID_KEYNAME[] = "AccountId"; - static constexpr const char RESOURCE_MAPPING_RESOURCES_KEYNAME[] = "AWSResourceMappings"; - static constexpr const char RESOURCE_MAPPING_NAMEID_KEYNAME[] = "Name/ID"; - static constexpr const char RESOURCE_MAPPING_REGION_KEYNAME[] = "Region"; - static constexpr const char RESOURCE_MAPPING_TYPE_KEYNAME[] = "Type"; - static constexpr const char RESOURCE_MAPPING_VERSION_KEYNAME[] = "Version"; + static constexpr const char ResourceMappingAccountIdKeyName[] = "AccountId"; + static constexpr const char ResourceMappingResourcesKeyName[] = "AWSResourceMappings"; + static constexpr const char ResourceMappingNameIdKeyName[] = "Name/ID"; + static constexpr const char ResourceMappingRegionKeyName[] = "Region"; + static constexpr const char ResourceMappingTypeKeyName[] = "Type"; + static constexpr const char ResourceMappingVersionKeyName[] = "Version"; // TODO: move this into an independent file under AWSCore gem, if resource mapping tool can reuse it - static constexpr const char RESOURCE_MAPPING_JSON_SCHEMA[] = + static constexpr const char ResourceMappingJsonSchema[] = R"({ "$schema": "http://json-schema.org/draft-04/schema", "type": "object", diff --git a/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingManager.h b/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingManager.h index 9200a9c4ff..6d22c55d2c 100644 --- a/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingManager.h +++ b/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingManager.h @@ -45,6 +45,35 @@ namespace AWSCore }; public: + static constexpr const char AWSResourceMappingManagerName[] = "AWSResourceMappingManager"; + static constexpr const char ManagerUnexpectedStatusErrorMessage[] = + "AWSResourceMappingManager is in unexpected status."; + static constexpr const char ResourceMappingFileInvalidPathErrorMessage[] = + "Failed to get resource mapping config file path."; + static constexpr const char ResourceMappingKeyNotFoundErrorMessage[] = + "Failed to find resource mapping key: %s"; + static constexpr const char ResourceMappingFileNotLoadedErrorMessage[] = + "Resource mapping config file is not loaded, please confirm %s is setup correctly."; + static constexpr const char ResourceMappingFileLoadFailureErrorMessage[] = + "Resource mapping config file failed to load, please confirm file is present and in correct format."; + static constexpr const char ResourceMappingRESTApiIdAndStageInconsistentErrorMessage[] = + "Resource mapping %s and %s have inconsistent region value, return empty service url."; + static constexpr const char ResourceMappingRESTApiInvalidServiceUrlErrorMessage[] = + "Unable to format REST Api url with RESTApiId=%s, RESTApiRegion=%s, RESTApiStage=%s, return empty service url."; + static constexpr const char ResourceMappingFileInvalidJsonFormatErrorMessage[] = + "Failed to read resource mapping config file: %s"; + static constexpr const char ResourceMappingFileInvalidSchemaErrorMessage[] = + "Failed to load resource mapping config file json schema."; + static constexpr const char ResourceMappingFileInvalidContentErrorMessage[] = + "Failed to parse resource mapping config file: %s"; + + enum class Status : AZ::u8 + { + NotLoaded = 0, + Ready = 1, + Error = 2 + }; + AWSResourceMappingManager(); ~AWSResourceMappingManager() = default; @@ -63,7 +92,12 @@ namespace AWSCore const AZStd::string& restApiIdKeyName, const AZStd::string& restApiStageKeyName) const override; void ReloadConfigFile(bool reloadConfigFileName = false) override; + Status GetStatus() const; + private: + // Get resource attribute error message based on the status + AZStd::string GetResourceAttributeErrorMessageByStatus(const AZStd::string& resourceKeyName) const; + // Get resource attribute from resource mappings AZStd::string GetResourceAttribute( AZStd::function getAttributeFunction, @@ -83,6 +117,7 @@ namespace AWSCore // Validate JSON document against schema bool ValidateJsonDocumentAgainstSchema(const rapidjson::Document& jsonDocument); + Status m_status; // Resource mapping related data AZStd::string m_defaultAccountId; AZStd::string m_defaultRegion; diff --git a/Gems/AWSCore/Code/Source/Configuration/AWSCoreConfiguration.cpp b/Gems/AWSCore/Code/Source/Configuration/AWSCoreConfiguration.cpp index 0445ea830e..3c0f48c058 100644 --- a/Gems/AWSCore/Code/Source/Configuration/AWSCoreConfiguration.cpp +++ b/Gems/AWSCore/Code/Source/Configuration/AWSCoreConfiguration.cpp @@ -20,7 +20,7 @@ namespace AWSCore { AWSCoreConfiguration::AWSCoreConfiguration() : m_sourceProjectFolder("") - , m_profileName(AWSCORE_DEFAULT_PROFILE_NAME) + , m_profileName(AWSCoreDefaultProfileName) , m_resourceMappingConfigFileName("") { } @@ -44,16 +44,16 @@ namespace AWSCore { if (m_sourceProjectFolder.empty()) { - AZ_Warning("AWSCoreConfiguration", false, "Failed to get source project folder path."); + AZ_Warning(AWSCoreConfigurationName, false, ProjectSourceFolderNotFoundErrorMessage); return ""; } if (m_resourceMappingConfigFileName.empty()) { - AZ_Warning("AWSCoreConfiguration", false, "Failed to get resource mapping config file name."); + AZ_Warning(AWSCoreConfigurationName, false, ResourceMappingFileNameNotFoundErrorMessage); return ""; } AZStd::string configFilePath = AZStd::string::format("%s/%s/%s", - m_sourceProjectFolder.c_str(), AWSCORE_RESOURCE_MAPPING_CONFIG_FOLDERNAME, m_resourceMappingConfigFileName.c_str()); + m_sourceProjectFolder.c_str(), AWSCoreResourceMappingConfigFolderName, m_resourceMappingConfigFileName.c_str()); AzFramework::StringFunc::Path::Normalize(configFilePath); return configFilePath; } @@ -68,17 +68,17 @@ namespace AWSCore { if (m_sourceProjectFolder.empty()) { - AZ_Warning("AWSCoreConfiguration", false, "Failed to get source project folder path."); + AZ_Warning(AWSCoreConfigurationName, false, ProjectSourceFolderNotFoundErrorMessage); return; } AZStd::string settingsRegistryPath = AZStd::string::format("%s/%s/%s", - m_sourceProjectFolder.c_str(), AZ::SettingsRegistryInterface::RegistryFolder, AWSCoreConfiguration::AWSCORE_CONFIGURATION_FILENAME); + m_sourceProjectFolder.c_str(), AZ::SettingsRegistryInterface::RegistryFolder, AWSCoreConfiguration::AWSCoreConfigurationFileName); AzFramework::StringFunc::Path::Normalize(settingsRegistryPath); if (!m_settingsRegistry.MergeSettingsFile(settingsRegistryPath, AZ::SettingsRegistryInterface::Format::JsonMergePatch, "")) { - AZ_Warning("AWSCoreConfiguration", false, "Failed to merge AWS core settings registry."); + AZ_Warning(AWSCoreConfigurationName, false, SettingsRegistryLoadFailureErrorMessage); return; } @@ -90,7 +90,7 @@ namespace AWSCore auto sourceProjectFolder = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); if (!sourceProjectFolder) { - AZ_Error("AWSCoreConfiguration", false, "Failed to initialize source project folder path."); + AZ_Error(AWSCoreConfigurationName, false, ProjectSourceFolderNotFoundErrorMessage); } else { @@ -102,24 +102,38 @@ namespace AWSCore { m_resourceMappingConfigFileName.clear(); auto resourceMappingConfigFileNamePath = AZStd::string::format("%s%s", - AZ::SettingsRegistryMergeUtils::OrganizationRootKey, AWSCORE_RESOURCE_MAPPING_CONFIG_FILENAME_KEY); + AZ::SettingsRegistryMergeUtils::OrganizationRootKey, AWSCoreResourceMappingConfigFileNameKey); if (!m_settingsRegistry.Get(m_resourceMappingConfigFileName, resourceMappingConfigFileNamePath)) { - AZ_Warning("AWSCoreConfiguration", false, "Failed to get resource mapping config file name from settings registry."); + AZ_Warning(AWSCoreConfigurationName, false, ResourceMappingFileNameNotFoundErrorMessage); } m_profileName.clear(); auto profileNamePath = AZStd::string::format( - "%s%s", AZ::SettingsRegistryMergeUtils::OrganizationRootKey, AWSCORE_PROFILENAME_KEY); + "%s%s", AZ::SettingsRegistryMergeUtils::OrganizationRootKey, AWSCoreProfileNameKey); if (!m_settingsRegistry.Get(m_profileName, profileNamePath)) { - AZ_Warning("AWSCoreConfiguration", false, "Failed to get profile name from settings registry, using default value instead."); - m_profileName = AWSCORE_DEFAULT_PROFILE_NAME; + AZ_Warning(AWSCoreConfigurationName, false, ProfileNameNotFoundErrorMessage); + m_profileName = AWSCoreDefaultProfileName; } } + void AWSCoreConfiguration::ResetSettingsRegistryData() + { + auto profileNamePath = AZStd::string::format("%s%s", + AZ::SettingsRegistryMergeUtils::OrganizationRootKey, AWSCoreProfileNameKey); + m_settingsRegistry.Remove(profileNamePath); + m_profileName.clear(); + + auto resourceMappingConfigFileNamePath = AZStd::string::format("%s%s", + AZ::SettingsRegistryMergeUtils::OrganizationRootKey, AWSCoreResourceMappingConfigFileNameKey); + m_settingsRegistry.Remove(resourceMappingConfigFileNamePath); + m_resourceMappingConfigFileName.clear(); + } + void AWSCoreConfiguration::ReloadConfiguration() { + ResetSettingsRegistryData(); InitSettingsRegistry(); } } // namespace AWSCore diff --git a/Gems/AWSCore/Code/Source/Credential/AWSDefaultCredentialHandler.cpp b/Gems/AWSCore/Code/Source/Credential/AWSDefaultCredentialHandler.cpp index ba7a8c72dd..bb195e487a 100644 --- a/Gems/AWSCore/Code/Source/Credential/AWSDefaultCredentialHandler.cpp +++ b/Gems/AWSCore/Code/Source/Credential/AWSDefaultCredentialHandler.cpp @@ -84,7 +84,7 @@ namespace AWSCore { AZ_Warning("AWSDefaultCredentialHandler", false, "Failed to get profile name, use default profile name instead"); SetProfileCredentialsProvider(Aws::MakeShared( - AWSDEFAULTCREDENTIALHANDLER_ALLOC_TAG, AWSCoreConfiguration::AWSCORE_DEFAULT_PROFILE_NAME)); + AWSDEFAULTCREDENTIALHANDLER_ALLOC_TAG, AWSCoreConfiguration::AWSCoreDefaultProfileName)); } else { diff --git a/Gems/AWSCore/Code/Source/ResourceMapping/AWSResourceMappingManager.cpp b/Gems/AWSCore/Code/Source/ResourceMapping/AWSResourceMappingManager.cpp index c87a7f99ba..efdba0e9e0 100644 --- a/Gems/AWSCore/Code/Source/ResourceMapping/AWSResourceMappingManager.cpp +++ b/Gems/AWSCore/Code/Source/ResourceMapping/AWSResourceMappingManager.cpp @@ -12,12 +12,14 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -25,7 +27,8 @@ namespace AWSCore { AWSResourceMappingManager::AWSResourceMappingManager() - : m_defaultAccountId("") + : m_status(Status::NotLoaded) + , m_defaultAccountId("") , m_defaultRegion("") , m_resourceMappings() { @@ -43,11 +46,27 @@ namespace AWSCore ResetResourceMappingsData(); } + AZStd::string AWSResourceMappingManager::GetResourceAttributeErrorMessageByStatus(const AZStd::string& resourceKeyName) const + { + switch (m_status) + { + case Status::NotLoaded: + return AZStd::string::format(ResourceMappingFileNotLoadedErrorMessage, AWSCoreConfiguration::AWSCoreConfigurationFileName); + case Status::Ready: + return AZStd::string::format(ResourceMappingKeyNotFoundErrorMessage, resourceKeyName.c_str()); + case Status::Error: + return ResourceMappingFileLoadFailureErrorMessage; + default: + return ManagerUnexpectedStatusErrorMessage; + } + } + AZStd::string AWSResourceMappingManager::GetDefaultAccountId() const { if (m_defaultAccountId.empty()) { - AZ_Warning("AWSResourceMappingManager", false, "Account Id should not be empty, please make sure config file is valid."); + AZ_Warning(AWSResourceMappingManagerName, false, + GetResourceAttributeErrorMessageByStatus(ResourceMappingAccountIdKeyName).c_str()); } return m_defaultAccountId; } @@ -56,7 +75,8 @@ namespace AWSCore { if (m_defaultRegion.empty()) { - AZ_Warning("AWSResourceMappingManager", false, "Region should not be empty, please make sure config file is valid."); + AZ_Warning(AWSResourceMappingManagerName, false, + GetResourceAttributeErrorMessageByStatus(ResourceMappingRegionKeyName).c_str()); } return m_defaultRegion; } @@ -100,8 +120,8 @@ namespace AWSCore AZStd::string AWSResourceMappingManager::GetServiceUrlByServiceName(const AZStd::string& serviceName) const { return GetServiceUrlByRESTApiIdAndStage( - AZStd::string::format("%s%s", serviceName.c_str(), AWS_FEATURE_GEM_RESTAPI_ID_KEYNAME_SUFFIX), - AZStd::string::format("%s%s", serviceName.c_str(), AWS_FEATURE_GEM_RESTAPI_STAGE_KEYNAME_SUFFIX)); + AZStd::string::format("%s%s", serviceName.c_str(), AWSFeatureGemRESTApiIdKeyNameSuffix), + AZStd::string::format("%s%s", serviceName.c_str(), AWSFeatureGemRESTApiStageKeyNameSuffix)); } AZStd::string AWSResourceMappingManager::GetServiceUrlByRESTApiIdAndStage( @@ -113,16 +133,13 @@ namespace AWSCore AZStd::string serviceRegion = GetResourceRegion(restApiIdKeyName); if (serviceRegion != GetResourceRegion(restApiStageKeyName)) { - AZ_Warning( - "AWSResourceMappingManager", false, "%s and %s have inconsistent region value, return empty service url.", + AZ_Warning(AWSResourceMappingManagerName, false, ResourceMappingRESTApiIdAndStageInconsistentErrorMessage, restApiIdKeyName.c_str(), restApiStageKeyName.c_str()); return ""; } AZStd::string serviceRESTApiUrl = AWSResourceMappingUtils::FormatRESTApiUrl(serviceRESTApiId, serviceRegion, serviceRESTApiStage); - AZ_Warning( - "AWSResourceMappingManager", !serviceRESTApiUrl.empty(), - "Unable to format REST Api url with RESTApiId=%s, RESTApiRegion=%s, RESTApiStage=%s, return empty service url.", + AZ_Warning(AWSResourceMappingManagerName, !serviceRESTApiUrl.empty(), ResourceMappingRESTApiInvalidServiceUrlErrorMessage, serviceRESTApiId.c_str(), serviceRegion.c_str(), serviceRESTApiStage.c_str()); return serviceRESTApiUrl; } @@ -136,16 +153,21 @@ namespace AWSCore return getAttributeFunction(iter->second); } - AZ_Warning("AWSResourceMappingManager", false, "Failed to find resource mapping key: %s.", resourceKeyName.c_str()); + AZ_Warning(AWSResourceMappingManagerName, false, GetResourceAttributeErrorMessageByStatus(resourceKeyName).c_str()); return ""; } + AWSResourceMappingManager::Status AWSResourceMappingManager::GetStatus() const + { + return m_status; + } + void AWSResourceMappingManager::ParseJsonDocument(const rapidjson::Document& jsonDocument) { - m_defaultAccountId = jsonDocument.FindMember(RESOURCE_MAPPING_ACCOUNTID_KEYNAME)->value.GetString(); - m_defaultRegion = jsonDocument.FindMember(RESOURCE_MAPPING_REGION_KEYNAME)->value.GetString(); + m_defaultAccountId = jsonDocument.FindMember(ResourceMappingAccountIdKeyName)->value.GetString(); + m_defaultRegion = jsonDocument.FindMember(ResourceMappingRegionKeyName)->value.GetString(); - auto resourceMappings = jsonDocument.FindMember(RESOURCE_MAPPING_RESOURCES_KEYNAME)->value.GetObject(); + auto resourceMappings = jsonDocument.FindMember(ResourceMappingResourcesKeyName)->value.GetObject(); for (auto mappingIter = resourceMappings.MemberBegin(); mappingIter != resourceMappings.MemberEnd(); mappingIter++) { auto mappingValue = mappingIter->value.GetObject(); @@ -162,16 +184,16 @@ namespace AWSCore const JsonObject& jsonObject) { AWSResourceMappingAttributes attributes; - if (jsonObject.HasMember(RESOURCE_MAPPING_ACCOUNTID_KEYNAME)) + if (jsonObject.HasMember(ResourceMappingAccountIdKeyName)) { - attributes.resourceAccountId = jsonObject.FindMember(RESOURCE_MAPPING_ACCOUNTID_KEYNAME)->value.GetString(); + attributes.resourceAccountId = jsonObject.FindMember(ResourceMappingAccountIdKeyName)->value.GetString(); } - attributes.resourceNameId = jsonObject.FindMember(RESOURCE_MAPPING_NAMEID_KEYNAME)->value.GetString(); - if (jsonObject.HasMember(RESOURCE_MAPPING_REGION_KEYNAME)) + attributes.resourceNameId = jsonObject.FindMember(ResourceMappingNameIdKeyName)->value.GetString(); + if (jsonObject.HasMember(ResourceMappingRegionKeyName)) { - attributes.resourceRegion = jsonObject.FindMember(RESOURCE_MAPPING_REGION_KEYNAME)->value.GetString(); + attributes.resourceRegion = jsonObject.FindMember(ResourceMappingRegionKeyName)->value.GetString(); } - attributes.resourceType = jsonObject.FindMember(RESOURCE_MAPPING_TYPE_KEYNAME)->value.GetString(); + attributes.resourceType = jsonObject.FindMember(ResourceMappingTypeKeyName)->value.GetString(); return attributes; } @@ -188,7 +210,7 @@ namespace AWSCore AWSCoreInternalRequestBus::BroadcastResult(configJsonPath, &AWSCoreInternalRequests::GetResourceMappingConfigFilePath); if (configJsonPath.empty()) { - AZ_Warning("AWSResourceMappingManager", false, "Failed to get resource mapping config file path."); + AZ_Warning(AWSResourceMappingManagerName, false, ResourceMappingFileInvalidPathErrorMessage); return; } @@ -201,20 +223,26 @@ namespace AWSCore if (!ValidateJsonDocumentAgainstSchema(jsonDocument)) { // Failed to satisfy the validation against json schema + m_status = Status::Error; return; } ParseJsonDocument(jsonDocument); } else { - AZ_Warning( - "AWSResourceMappingManager", false, "Failed to get read resource mapping config file: %s\n Error: %s", - configJsonPath.c_str(), readJsonOutcome.GetError().c_str()); + m_status = Status::Error; + AZ_Warning(AWSResourceMappingManagerName, false, + ResourceMappingFileInvalidJsonFormatErrorMessage, readJsonOutcome.GetError().c_str()); + return; } + + // Resource mapping config file gets loaded successfully + m_status = Status::Ready; } void AWSResourceMappingManager::ResetResourceMappingsData() { + m_status = Status::NotLoaded; m_defaultAccountId = ""; m_defaultRegion = ""; m_resourceMappings.clear(); @@ -223,9 +251,9 @@ namespace AWSCore bool AWSResourceMappingManager::ValidateJsonDocumentAgainstSchema(const rapidjson::Document& jsonDocument) { rapidjson::Document jsonSchemaDocument; - if (jsonSchemaDocument.Parse(RESOURCE_MAPPING_JSON_SCHEMA).HasParseError()) + if (jsonSchemaDocument.Parse(ResourceMappingJsonSchema).HasParseError()) { - AZ_Error("AWSResourceMappingManager", false, "Invalid resource mapping json schema."); + AZ_Error(AWSResourceMappingManagerName, false, ResourceMappingFileInvalidSchemaErrorMessage); return false; } @@ -235,12 +263,10 @@ namespace AWSCore if (!jsonDocument.Accept(validator)) { rapidjson::StringBuffer error; - validator.GetInvalidSchemaPointer().StringifyUriFragment(error); - AZ_Warning("AWSResourceMappingManager", false, "Failed to load config file, invalid schema: %s.", error.GetString()); - AZ_Warning("AWSResourceMappingManager", false, "Failed to load config file, invalid keyword: %s.", validator.GetInvalidSchemaKeyword()); - error.Clear(); - validator.GetInvalidDocumentPointer().StringifyUriFragment(error); - AZ_Warning("AWSResourceMappingManager", false, "Failed to load config file, invalid document: %s.", error.GetString()); + rapidjson::PrettyWriter writer(error); + validator.GetError().Accept(writer); + AZ_Warning(AWSResourceMappingManagerName, false, ResourceMappingFileInvalidContentErrorMessage, error.GetString()); + return false; } return true; diff --git a/Gems/AWSCore/Code/Source/ResourceMapping/AWSResourceMappingUtils.cpp b/Gems/AWSCore/Code/Source/ResourceMapping/AWSResourceMappingUtils.cpp index 74be3bf914..7d17a86909 100644 --- a/Gems/AWSCore/Code/Source/ResourceMapping/AWSResourceMappingUtils.cpp +++ b/Gems/AWSCore/Code/Source/ResourceMapping/AWSResourceMappingUtils.cpp @@ -18,8 +18,8 @@ namespace AWSCore namespace AWSResourceMappingUtils { // https://docs.aws.amazon.com/general/latest/gr/apigateway.html - static constexpr char RESTAPI_URL_FORMAT[] = "https://%s.execute-api.%s.amazonaws.com/%s"; - static constexpr char RESTAPI_CHINA_URL_FORMAT[] = "https://%s.execute-api.%s.amazonaws.com.cn/%s"; + static constexpr char RESTApiUrlFormat[] = "https://%s.execute-api.%s.amazonaws.com/%s"; + static constexpr char RESTApiChinaUrlFormat[] = "https://%s.execute-api.%s.amazonaws.com.cn/%s"; AZStd::string FormatRESTApiUrl( const AZStd::string& restApiId, const AZStd::string& restApiRegion, const AZStd::string& restApiStage) @@ -27,14 +27,14 @@ namespace AWSCore // https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-call-api.html if (!restApiId.empty() && !restApiRegion.empty() && !restApiStage.empty()) { - if (restApiRegion.rfind(AWS_CHINA_REGION_PREFIX, 0) == 0) + if (restApiRegion.rfind(AWSChinaRegionPrefix, 0) == 0) { - return AZStd::string::format(RESTAPI_CHINA_URL_FORMAT, + return AZStd::string::format(RESTApiChinaUrlFormat, restApiId.c_str(), restApiRegion.c_str(), restApiStage.c_str()); } else { - return AZStd::string::format(RESTAPI_URL_FORMAT, + return AZStd::string::format(RESTApiUrlFormat, restApiId.c_str(), restApiRegion.c_str(), restApiStage.c_str()); } } diff --git a/Gems/AWSCore/Code/Tests/Configuration/AWSCoreConfigurationTest.cpp b/Gems/AWSCore/Code/Tests/Configuration/AWSCoreConfigurationTest.cpp index dab405dee4..b3c2b8d2ca 100644 --- a/Gems/AWSCore/Code/Tests/Configuration/AWSCoreConfigurationTest.cpp +++ b/Gems/AWSCore/Code/Tests/Configuration/AWSCoreConfigurationTest.cpp @@ -46,7 +46,7 @@ public: void CreateTestSetRegFile(const AZStd::string& setregContent) { m_normalizedSetRegFilePath = AZStd::string::format("%s/%s", - m_normalizedSetRegFolderPath.c_str(), AWSCore::AWSCoreConfiguration::AWSCORE_CONFIGURATION_FILENAME); + m_normalizedSetRegFolderPath.c_str(), AWSCore::AWSCoreConfiguration::AWSCoreConfigurationFileName); AzFramework::StringFunc::Path::Normalize(m_normalizedSetRegFilePath); CreateTestFile(m_normalizedSetRegFilePath, setregContent); } @@ -177,7 +177,7 @@ TEST_F(AWSCoreConfigurationTest, ReloadConfiguration_LoadValidSettingsRegistryAf auto actualConfigFilePath = m_awsCoreConfiguration->GetResourceMappingConfigFilePath(); auto actualProfileName = m_awsCoreConfiguration->GetProfileName(); EXPECT_TRUE(actualConfigFilePath.empty()); - EXPECT_TRUE(actualProfileName == AWSCoreConfiguration::AWSCORE_DEFAULT_PROFILE_NAME); + EXPECT_TRUE(actualProfileName == AWSCoreConfiguration::AWSCoreDefaultProfileName); CreateTestSetRegFile(TEST_VALID_RESOURCE_MAPPING_SETREG); m_awsCoreConfiguration->ReloadConfiguration(); @@ -185,5 +185,24 @@ TEST_F(AWSCoreConfigurationTest, ReloadConfiguration_LoadValidSettingsRegistryAf actualConfigFilePath = m_awsCoreConfiguration->GetResourceMappingConfigFilePath(); actualProfileName = m_awsCoreConfiguration->GetProfileName(); EXPECT_FALSE(actualConfigFilePath.empty()); - EXPECT_TRUE(actualProfileName != AWSCoreConfiguration::AWSCORE_DEFAULT_PROFILE_NAME); + EXPECT_TRUE(actualProfileName != AWSCoreConfiguration::AWSCoreDefaultProfileName); +} + +TEST_F(AWSCoreConfigurationTest, ReloadConfiguration_LoadInvalidSettingsRegistryAfterValidOne_ReturnEmptyConfigFilePath) +{ + CreateTestSetRegFile(TEST_VALID_RESOURCE_MAPPING_SETREG); + m_awsCoreConfiguration->InitConfig(); + + auto actualConfigFilePath = m_awsCoreConfiguration->GetResourceMappingConfigFilePath(); + auto actualProfileName = m_awsCoreConfiguration->GetProfileName(); + EXPECT_FALSE(actualConfigFilePath.empty()); + EXPECT_TRUE(actualProfileName != AWSCoreConfiguration::AWSCoreDefaultProfileName); + + CreateTestSetRegFile(TEST_INVALID_RESOURCE_MAPPING_SETREG); + m_awsCoreConfiguration->ReloadConfiguration(); + + actualConfigFilePath = m_awsCoreConfiguration->GetResourceMappingConfigFilePath(); + actualProfileName = m_awsCoreConfiguration->GetProfileName(); + EXPECT_TRUE(actualConfigFilePath.empty()); + EXPECT_TRUE(actualProfileName == AWSCoreConfiguration::AWSCoreDefaultProfileName); } diff --git a/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp b/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp index 73a28f97cb..3adebc9a24 100644 --- a/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp +++ b/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp @@ -98,7 +98,7 @@ public: "AWSResourceMappingManager", AZ::Uuid::CreateRandom().ToString(false, false).c_str()); AzFramework::StringFunc::Path::Normalize(m_normalizedSourceProjectFolder); m_normalizedConfigFolderPath = AZStd::string::format("%s/%s/", - m_normalizedSourceProjectFolder.c_str(), AWSCore::AWSCoreConfiguration::AWSCORE_RESOURCE_MAPPING_CONFIG_FOLDERNAME); + m_normalizedSourceProjectFolder.c_str(), AWSCore::AWSCoreConfiguration::AWSCoreResourceMappingConfigFolderName); AzFramework::StringFunc::Path::Normalize(m_normalizedConfigFolderPath); AWSCoreInternalRequestBus::Handler::BusConnect(); } @@ -178,6 +178,7 @@ TEST_F(AWSResourceMappingManagerTest, ActivateManager_ParseInvalidConfigFile_Con EXPECT_EQ(m_reloadConfigurationCounter, 1); EXPECT_TRUE(actualAccountId.empty()); EXPECT_TRUE(actualRegion.empty()); + EXPECT_TRUE(m_resourceMappingManager->GetStatus() == AWSResourceMappingManager::Status::Error); } TEST_F(AWSResourceMappingManagerTest, ActivateManager_ParseValidConfigFile_ConfigDataIsNotEmpty) @@ -192,6 +193,7 @@ TEST_F(AWSResourceMappingManagerTest, ActivateManager_ParseValidConfigFile_Confi EXPECT_EQ(m_reloadConfigurationCounter, 1); EXPECT_FALSE(actualAccountId.empty()); EXPECT_FALSE(actualRegion.empty()); + EXPECT_TRUE(m_resourceMappingManager->GetStatus() == AWSResourceMappingManager::Status::Ready); } TEST_F(AWSResourceMappingManagerTest, ActivateManager_ParseValidConfigFile_ConfigDataIsNotEmptyWithMultithreadCalls) @@ -230,11 +232,13 @@ TEST_F(AWSResourceMappingManagerTest, DeactivateManager_AfterActivatingWithValid AWSResourceMappingRequestBus::BroadcastResult(actualRegion, &AWSResourceMappingRequests::GetDefaultRegion); EXPECT_FALSE(actualAccountId.empty()); EXPECT_FALSE(actualRegion.empty()); + EXPECT_TRUE(m_resourceMappingManager->GetStatus() == AWSResourceMappingManager::Status::Ready); m_resourceMappingManager->DeactivateManager(); EXPECT_TRUE(m_resourceMappingManager->GetDefaultAccountId().empty()); EXPECT_TRUE(m_resourceMappingManager->GetDefaultRegion().empty()); + EXPECT_TRUE(m_resourceMappingManager->GetStatus() == AWSResourceMappingManager::Status::NotLoaded); } TEST_F(AWSResourceMappingManagerTest, GetDefaultAccountId_AfterParsingValidConfigFile_GetExpectedDefaultAccountId) @@ -416,6 +420,7 @@ TEST_F(AWSResourceMappingManagerTest, ReloadConfigFile_ParseValidConfigFileAfter EXPECT_EQ(m_reloadConfigurationCounter, 1); EXPECT_TRUE(actualAccountId.empty()); EXPECT_TRUE(actualRegion.empty()); + EXPECT_TRUE(m_resourceMappingManager->GetStatus() == AWSResourceMappingManager::Status::Error); CreateTestConfigFile(TEST_VALID_RESOURCE_MAPPING_CONFIG_FILE); m_resourceMappingManager->ReloadConfigFile(); @@ -425,6 +430,7 @@ TEST_F(AWSResourceMappingManagerTest, ReloadConfigFile_ParseValidConfigFileAfter EXPECT_EQ(m_reloadConfigurationCounter, 1); EXPECT_FALSE(actualAccountId.empty()); EXPECT_FALSE(actualRegion.empty()); + EXPECT_TRUE(m_resourceMappingManager->GetStatus() == AWSResourceMappingManager::Status::Ready); } TEST_F(AWSResourceMappingManagerTest, ReloadConfigFile_ReloadConfigFileNameAndParseValidConfigFile_ConfigDataGetParsed) @@ -435,6 +441,7 @@ TEST_F(AWSResourceMappingManagerTest, ReloadConfigFile_ReloadConfigFileNameAndPa EXPECT_EQ(m_reloadConfigurationCounter, 1); EXPECT_FALSE(m_resourceMappingManager->GetDefaultAccountId().empty()); EXPECT_FALSE(m_resourceMappingManager->GetDefaultRegion().empty()); + EXPECT_TRUE(m_resourceMappingManager->GetStatus() == AWSResourceMappingManager::Status::Ready); } TEST_F(AWSResourceMappingManagerTest, ReloadConfigFile_MissingSetRegFile_ConfigDataIsNotParsed) @@ -444,4 +451,5 @@ TEST_F(AWSResourceMappingManagerTest, ReloadConfigFile_MissingSetRegFile_ConfigD EXPECT_EQ(m_reloadConfigurationCounter, 1); EXPECT_TRUE(m_resourceMappingManager->GetDefaultAccountId().empty()); EXPECT_TRUE(m_resourceMappingManager->GetDefaultRegion().empty()); + EXPECT_TRUE(m_resourceMappingManager->GetStatus() == AWSResourceMappingManager::Status::NotLoaded); } diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Decals/DecalFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Decals/DecalFeatureProcessorInterface.h index 214feb2040..a7aebf5aa4 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Decals/DecalFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Decals/DecalFeatureProcessorInterface.h @@ -88,7 +88,10 @@ namespace AZ //! Sets the transform of the decal //! Equivalent to calling SetDecalPosition() + SetDecalOrientation() + SetDecalHalfSize() + //! @{ virtual void SetDecalTransform(DecalHandle handle, const AZ::Transform& world) = 0; + virtual void SetDecalTransform(DecalHandle handle, const AZ::Transform& world, const AZ::Vector3& nonUniformScale) = 0; + //! @} //! Sets the material information for this decal virtual void SetDecalMaterial(DecalHandle handle, const AZ::Data::AssetId) = 0; diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.cpp index 7abc6698fa..55fa633e5d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.cpp @@ -264,7 +264,12 @@ namespace AZ void DecalFeatureProcessor::SetDecalTransform(DecalHandle handle, const AZ::Transform& world) { - // https://jira.agscollab.com/browse/ATOM-4330 + SetDecalTransform(handle, world, AZ::Vector3::CreateOne()); + } + + void DecalFeatureProcessor::SetDecalTransform(DecalHandle handle, const AZ::Transform& world, const AZ::Vector3& nonUniformScale) + { + // ATOM-4330 // Original Open 3D Engine uploads a 4x4 matrix rather than quaternion, rotation, scale. // That is more memory but less calculation because it is doing a matrix inverse rather than a polar decomposition // I've done some experiments and uploading a 3x4 transform matrix with 3x3 matrix inverse should be possible @@ -274,7 +279,7 @@ namespace AZ if (handle.IsValid()) { Quaternion orientation = world.GetRotation(); - Vector3 scale = world.GetScale(); + Vector3 scale = world.GetScale() * nonUniformScale; SetDecalHalfSize(handle, scale); SetDecalPosition(handle, world.GetTranslation()); diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.h index 9c4acf6322..3b99715d5a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.h @@ -73,7 +73,10 @@ namespace AZ //! Sets the transform of the decal //! Equivalent to calling SetDecalPosition() + SetDecalOrientation() + SetDecalHalfSize() + //! @{ void SetDecalTransform(DecalHandle handle, const AZ::Transform& world) override; + void SetDecalTransform(DecalHandle handle, const AZ::Transform& world, const AZ::Vector3& nonUniformScale) override; + //! @} //! Sets the material information for this decal void SetDecalMaterial(DecalHandle handle, const AZ::Data::AssetId) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp index 9d1ea4e680..4000df646d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp @@ -270,10 +270,16 @@ namespace AZ } void DecalTextureArrayFeatureProcessor::SetDecalTransform(DecalHandle handle, const AZ::Transform& world) + { + SetDecalTransform(handle, world, AZ::Vector3::CreateOne()); + } + + void DecalTextureArrayFeatureProcessor::SetDecalTransform(DecalHandle handle, const AZ::Transform& world, + const AZ::Vector3& nonUniformScale) { if (handle.IsValid()) { - SetDecalHalfSize(handle, world.GetScale()); + SetDecalHalfSize(handle, nonUniformScale * world.GetScale()); SetDecalPosition(handle, world.GetTranslation()); SetDecalOrientation(handle, world.GetRotation()); diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h index 7ab073c7f9..825e461fc2 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h @@ -82,7 +82,10 @@ namespace AZ //! Sets the transform of the decal //! Equivalent to calling SetDecalPosition() + SetDecalOrientation() + SetDecalHalfSize() + //! @{ void SetDecalTransform(const DecalHandle handle, const AZ::Transform& world) override; + void SetDecalTransform(const DecalHandle handle, const AZ::Transform& world, const AZ::Vector3& nonUniformScale) override; + //! @} //! Sets the material information for this decal void SetDecalMaterial(const DecalHandle handle, const AZ::Data::AssetId id) override; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorGroupHeaderWidget.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorGroupHeaderWidget.h index d1beed1a65..bba299187b 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorGroupHeaderWidget.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorGroupHeaderWidget.h @@ -15,6 +15,7 @@ #if !defined(Q_MOC_RUN) #include #include +#include #include #endif @@ -31,7 +32,11 @@ namespace AtomToolsFramework void SetExpanded(bool expanded); bool IsExpanded() const; + Q_SIGNALS: + void clicked(QMouseEvent* event); + protected: + void mousePressEvent(QMouseEvent* event) override; void paintEvent(QPaintEvent* event) override; private: diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h index 5f16894a0c..81b512faf2 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h @@ -55,6 +55,12 @@ namespace AtomToolsFramework //! Calls Rebuild for all InspectorGroupWidget, allowing for destructive UI changes virtual void RebuildAll() = 0; + + //! Expands all groups and headers + virtual void ExpandAll() = 0; + + //! Collapses all groups and headers + virtual void CollapseAll() = 0; }; using InspectorRequestBus = AZ::EBus; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h index 9f8df2da71..b0932b3b04 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h @@ -29,11 +29,8 @@ namespace Ui namespace AtomToolsFramework { - class InspectorPropertyGroupWidget; -} + class InspectorGroupHeaderWidget; -namespace AtomToolsFramework -{ //! Provides controls for viewing and editing object settings. //! The settings can be divided into groups, with each one showing a subset of properties. class InspectorWidget @@ -66,8 +63,15 @@ namespace AtomToolsFramework void RefreshAll() override; void RebuildAll() override; + void ExpandAll() override; + void CollapseAll() override; + private: + void OnHeaderClicked(QMouseEvent* event, InspectorGroupHeaderWidget* groupHeader, QWidget* groupWidget); + QVBoxLayout* m_layout = nullptr; QScopedPointer m_ui; + AZStd::vector m_headers; + AZStd::vector m_groups; }; } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorGroupHeaderWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorGroupHeaderWidget.cpp index 2928d745c1..41cc1e4a50 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorGroupHeaderWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorGroupHeaderWidget.cpp @@ -14,10 +14,10 @@ #include #include -#include -#include #include +#include #include +#include #include namespace AtomToolsFramework @@ -44,6 +44,11 @@ namespace AtomToolsFramework return m_expanded; } + void InspectorGroupHeaderWidget::mousePressEvent(QMouseEvent* event) + { + emit clicked(event); + } + void InspectorGroupHeaderWidget::paintEvent([[maybe_unused]] QPaintEvent* event) { QPainter painter(this); @@ -52,19 +57,10 @@ namespace AtomToolsFramework auto& icon = m_expanded ? m_iconExpanded : m_iconCollapsed; const QRect iconRect(5, (geometry().height() / 2) - (iconSize.height() / 2), iconSize.width(), iconSize.height()); - style->drawItemPixmap(&painter, - iconRect, - Qt::AlignLeft | Qt::AlignVCenter, - icon.scaledToWidth(iconSize.width())); + style->drawItemPixmap(&painter, iconRect, Qt::AlignLeft | Qt::AlignVCenter, icon.scaledToWidth(iconSize.width())); const auto textRect = QRect(25, 0, geometry().width() - 21, geometry().height()); - style->drawItemText(&painter, - textRect, - Qt::AlignLeft | Qt::AlignVCenter, - QPalette(), - true, - text(), - QPalette::HighlightedText); + style->drawItemText(&painter, textRect, Qt::AlignLeft | Qt::AlignVCenter, QPalette(), true, text(), QPalette::HighlightedText); } } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp index 31a291c845..ec5f9893bd 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp @@ -10,12 +10,13 @@ * */ +#include #include #include #include -#include #include +#include #include #include @@ -38,6 +39,8 @@ namespace AtomToolsFramework m_layout = new QVBoxLayout(m_ui->m_propertyContent); m_layout->setContentsMargins(0, 0, 0, 0); m_layout->setSpacing(0); + m_headers.clear(); + m_groups.clear(); } void InspectorWidget::AddGroupsBegin() @@ -52,8 +55,7 @@ namespace AtomToolsFramework m_layout->addStretch(); // Scroll to top whenever there is new content - m_ui->m_propertyScrollArea->verticalScrollBar()->setValue( - m_ui->m_propertyScrollArea->verticalScrollBar()->minimum()); + m_ui->m_propertyScrollArea->verticalScrollBar()->setValue(m_ui->m_propertyScrollArea->verticalScrollBar()->minimum()); setUpdatesEnabled(true); } @@ -68,15 +70,15 @@ namespace AtomToolsFramework groupHeader->setText(groupDisplayName.c_str()); groupHeader->setToolTip(groupDescription.c_str()); m_layout->addWidget(groupHeader); + m_headers.push_back(groupHeader); groupWidget->setObjectName(groupNameId.c_str()); groupWidget->setParent(m_ui->m_propertyContent); m_layout->addWidget(groupWidget); + m_groups.push_back(groupWidget); - connect(groupHeader, &AzQtComponents::ExtendedLabel::clicked, this, [groupHeader, groupWidget]() - { - groupHeader->SetExpanded(!groupHeader->IsExpanded()); - groupWidget->setVisible(groupHeader->IsExpanded()); + connect(groupHeader, &InspectorGroupHeaderWidget::clicked, this, [this, groupHeader, groupWidget](QMouseEvent* event) { + OnHeaderClicked(event, groupHeader, groupWidget); }); } @@ -111,6 +113,57 @@ namespace AtomToolsFramework groupWidget->Rebuild(); } } + + void InspectorWidget::ExpandAll() + { + for (auto headerWidget : m_headers) + { + headerWidget->SetExpanded(true); + } + for (auto groupWidget : m_groups) + { + groupWidget->setVisible(true); + } + } + + void InspectorWidget::CollapseAll() + { + for (auto headerWidget : m_headers) + { + headerWidget->SetExpanded(false); + } + for (auto groupWidget : m_groups) + { + groupWidget->setVisible(false); + } + } + + void InspectorWidget::OnHeaderClicked(QMouseEvent* event, InspectorGroupHeaderWidget* groupHeader, QWidget* groupWidget) + { + if (event->button() == Qt::MouseButton::LeftButton) + { + groupHeader->SetExpanded(!groupHeader->IsExpanded()); + groupWidget->setVisible(groupHeader->IsExpanded()); + return; + } + + if (event->button() == Qt::MouseButton::RightButton) + { + QMenu menu; + menu.addAction("Expand", [groupHeader, groupWidget]() { + groupHeader->SetExpanded(true); + groupWidget->setVisible(true); + })->setEnabled(!groupHeader->IsExpanded()); + menu.addAction("Collapse", [groupHeader, groupWidget]() { + groupHeader->SetExpanded(false); + groupWidget->setVisible(false); + })->setEnabled(groupHeader->IsExpanded()); + menu.addAction("Expand All", [this]() { ExpandAll(); }); + menu.addAction("Collapse All", [this]() { CollapseAll(); }); + menu.exec(event->globalPos()); + return; + } + } } // namespace AtomToolsFramework #include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Decals/DecalComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Decals/DecalComponentController.cpp index 22a7e1c6c0..3c748e352e 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Decals/DecalComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Decals/DecalComponentController.cpp @@ -75,6 +75,12 @@ namespace AZ incompatible.push_back(AZ_CRC_CE("DecalService")); } + void DecalComponentController::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) + { + dependent.push_back(AZ_CRC_CE("TransformService")); + dependent.push_back(AZ_CRC_CE("NonUniformScaleService")); + } + DecalComponentController::DecalComponentController(const DecalComponentConfig& config) : m_configuration(config) { @@ -90,6 +96,11 @@ namespace AZ m_handle = m_featureProcessor->AcquireDecal(); } + m_cachedNonUniformScale = AZ::Vector3::CreateOne(); + AZ::NonUniformScaleRequestBus::EventResult(m_cachedNonUniformScale, m_entityId, &AZ::NonUniformScaleRequests::GetScale); + AZ::NonUniformScaleRequestBus::Event(m_entityId, &AZ::NonUniformScaleRequests::RegisterScaleChangedEvent, + m_nonUniformScaleChangedHandler); + AZ::Transform local, world; AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::GetLocalAndWorld, local, world); OnTransformChanged(local, world); @@ -103,6 +114,7 @@ namespace AZ { DecalRequestBus::Handler::BusDisconnect(m_entityId); TransformNotificationBus::Handler::BusDisconnect(m_entityId); + m_nonUniformScaleChangedHandler.Disconnect(); if (m_featureProcessor) { m_featureProcessor->ReleaseDecal(m_handle); @@ -125,7 +137,18 @@ namespace AZ { if (m_featureProcessor) { - m_featureProcessor->SetDecalTransform(m_handle, world); + m_featureProcessor->SetDecalTransform(m_handle, world, m_cachedNonUniformScale); + } + } + + void DecalComponentController::HandleNonUniformScaleChange(const AZ::Vector3& nonUniformScale) + { + m_cachedNonUniformScale = nonUniformScale; + if (m_featureProcessor) + { + AZ::Transform world = AZ::Transform::CreateIdentity(); + AZ::TransformBus::EventResult(world, m_entityId, &AZ::TransformBus::Events::GetWorldTM); + m_featureProcessor->SetDecalTransform(m_handle, world, nonUniformScale); } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Decals/DecalComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Decals/DecalComponentController.h index dc6b6e70ea..14204c43dc 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Decals/DecalComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Decals/DecalComponentController.h @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -33,6 +34,7 @@ namespace AZ static void Reflect(AZ::ReflectContext* context); static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); + static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); DecalComponentController() = default; DecalComponentController(const DecalComponentConfig& config); @@ -64,11 +66,18 @@ namespace AZ void OpacityChanged(); void SortKeyChanged(); void MaterialChanged(); + void HandleNonUniformScaleChange(const AZ::Vector3& nonUniformScale); DecalComponentConfig m_configuration; DecalFeatureProcessorInterface* m_featureProcessor = nullptr; DecalFeatureProcessorInterface::DecalHandle m_handle; EntityId m_entityId; + AZ::Vector3 m_cachedNonUniformScale = AZ::Vector3::CreateOne(); + + AZ::NonUniformScaleChangedEvent::Handler m_nonUniformScaleChangedHandler + { + [&](const AZ::Vector3& nonUniformScale) { HandleNonUniformScaleChange(nonUniformScale); } + }; }; } // namespace Render } // AZ namespace diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp index deab9d2715..70627fd2f1 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp @@ -131,6 +131,7 @@ namespace AZ void MeshComponentController::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) { dependent.push_back(AZ_CRC("TransformService", 0x8ee22c50)); + dependent.push_back(AZ_CRC_CE("NonUniformScaleService")); } void MeshComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) diff --git a/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.cpp b/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.cpp index 907bd66cb8..4d5ec5e2f7 100644 --- a/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.cpp +++ b/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.cpp @@ -54,11 +54,6 @@ namespace LmbrCentral return "Icons/Components/Decal.svg"; } - AZ::Uuid MaterialAssetTypeInfo::GetComponentTypeId() const - { - return AZ::Uuid("{BA3890BD-D2E7-4DB6-95CD-7E7D5525567A}"); - } - // DccMaterialAssetTypeInfo DccMaterialAssetTypeInfo::~DccMaterialAssetTypeInfo() diff --git a/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.h b/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.h index b7f3294e89..7e9c9e5fb4 100644 --- a/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.h +++ b/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.h @@ -30,7 +30,6 @@ namespace LmbrCentral const char* GetAssetTypeDisplayName() const override; const char* GetGroup() const override; const char* GetBrowserIcon() const override; - AZ::Uuid GetComponentTypeId() const override; ////////////////////////////////////////////////////////////////////////////////////////////// void Register(); diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp index e4596b5334..92aa1dddc7 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp @@ -58,7 +58,7 @@ namespace ScriptCanvasEditor } else { - resultHash = ScriptCanvas::NodeUtils::ConstructMethodNodeIdentifier(classMethodTreeItem->GetClassMethodName(), classMethodTreeItem->GetMethodName()); + resultHash = ScriptCanvas::NodeUtils::ConstructMethodNodeIdentifier(classMethodTreeItem->GetClassMethodName(), classMethodTreeItem->GetMethodName(), classMethodTreeItem->GetPropertyStatus()); } } else if (auto globalMethodTreeItem = azrtti_cast(treeItem); globalMethodTreeItem != nullptr) diff --git a/Gems/ScriptCanvas/Code/Editor/Nodes/NodeCreateUtils.cpp b/Gems/ScriptCanvas/Code/Editor/Nodes/NodeCreateUtils.cpp index 62905947a8..07c96aba82 100644 --- a/Gems/ScriptCanvas/Code/Editor/Nodes/NodeCreateUtils.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Nodes/NodeCreateUtils.cpp @@ -167,7 +167,7 @@ namespace ScriptCanvasEditor::Nodes return nodeIdPair; } - NodeIdPair CreateObjectMethodNode(AZStd::string_view className, AZStd::string_view methodName, const ScriptCanvas::ScriptCanvasId& scriptCanvasId) + NodeIdPair CreateObjectMethodNode(AZStd::string_view className, AZStd::string_view methodName, const ScriptCanvas::ScriptCanvasId& scriptCanvasId, ScriptCanvas::PropertyStatus propertyStatus) { AZ_PROFILE_TIMER("ScriptCanvas", __FUNCTION__); NodeIdPair nodeIds; @@ -181,7 +181,7 @@ namespace ScriptCanvasEditor::Nodes auto* methodNode = azrtti_cast(node); ScriptCanvas::NamespacePath emptyNamespacePath; - methodNode->InitializeBehaviorMethod(emptyNamespacePath, className, methodName); + methodNode->InitializeBehaviorMethod(emptyNamespacePath, className, methodName, propertyStatus); AZStd::string_view displayName = methodNode->GetName(); scriptCanvasEntity->SetName(AZStd::string::format("SC-Node(%.*s)", aznumeric_cast(displayName.size()), displayName.data())); @@ -208,7 +208,7 @@ namespace ScriptCanvasEditor::Nodes auto* methodNode = azrtti_cast(node); ScriptCanvas::NamespacePath emptyNamespacePath; - methodNode->InitializeBehaviorMethod(emptyNamespacePath, className, methodName); + methodNode->InitializeBehaviorMethod(emptyNamespacePath, className, methodName, ScriptCanvas::PropertyStatus::None); AZStd::string_view displayName = methodNode->GetName(); scriptCanvasEntity->SetName(AZStd::string::format("SC-Node(%.*s)", aznumeric_cast(displayName.size()), displayName.data())); diff --git a/Gems/ScriptCanvas/Code/Editor/Nodes/NodeCreateUtils.h b/Gems/ScriptCanvas/Code/Editor/Nodes/NodeCreateUtils.h index fa81ccfe8e..f4f0378333 100644 --- a/Gems/ScriptCanvas/Code/Editor/Nodes/NodeCreateUtils.h +++ b/Gems/ScriptCanvas/Code/Editor/Nodes/NodeCreateUtils.h @@ -34,7 +34,7 @@ namespace ScriptCanvasEditor::Nodes AZStd::pair CreateAndGetNode(const AZ::Uuid& classData, const ScriptCanvas::ScriptCanvasId& scriptCanvasId, const StyleConfiguration& styleConfiguration, AZStd::function = nullptr); NodeIdPair CreateNode(const AZ::Uuid& classData, const ScriptCanvas::ScriptCanvasId& scriptCanvasId, const StyleConfiguration& styleConfiguration); NodeIdPair CreateEntityNode(const AZ::EntityId& sourceId, const ScriptCanvas::ScriptCanvasId& scriptCanvasId); - NodeIdPair CreateObjectMethodNode(AZStd::string_view className, AZStd::string_view methodName, const ScriptCanvas::ScriptCanvasId& scriptCanvasId); + NodeIdPair CreateObjectMethodNode(AZStd::string_view className, AZStd::string_view methodName, const ScriptCanvas::ScriptCanvasId& scriptCanvasId, ScriptCanvas::PropertyStatus propertyStatus); NodeIdPair CreateObjectMethodOverloadNode(AZStd::string_view className, AZStd::string_view methodName, const ScriptCanvas::ScriptCanvasId& scriptCanvasGraphId); NodeIdPair CreateGlobalMethodNode(AZStd::string_view methodName, const ScriptCanvas::ScriptCanvasId& scriptCanvasId); NodeIdPair CreateEbusWrapperNode(AZStd::string_view busName, const ScriptCanvas::ScriptCanvasId& scriptCanvasId); diff --git a/Gems/ScriptCanvas/Code/Editor/Nodes/NodeDisplayUtils.cpp b/Gems/ScriptCanvas/Code/Editor/Nodes/NodeDisplayUtils.cpp index a903c9f885..c3929e6bc4 100644 --- a/Gems/ScriptCanvas/Code/Editor/Nodes/NodeDisplayUtils.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Nodes/NodeDisplayUtils.cpp @@ -327,12 +327,14 @@ namespace ScriptCanvasEditor::Nodes contextGroup = TranslationContextGroup::EbusSender; break; case ScriptCanvas::MethodType::Member: + case ScriptCanvas::MethodType::Getter: + case ScriptCanvas::MethodType::Setter: case ScriptCanvas::MethodType::Free: graphCanvasEntity->CreateComponent(); contextGroup = TranslationContextGroup::ClassMethod; break; default: - AZ_Error("ScriptCanvas", false, "Invalid method node type, node creation failed. This node nodes to be deleted."); + AZ_Error("ScriptCanvas", false, "Invalid method node type, node creation failed. This node needs to be deleted."); break; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/EBusNodePaletteTreeItemTypes.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/EBusNodePaletteTreeItemTypes.cpp index 4ae7d94560..474af058d3 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/EBusNodePaletteTreeItemTypes.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/EBusNodePaletteTreeItemTypes.cpp @@ -52,14 +52,16 @@ namespace ScriptCanvasEditor ->Field("BusName", &CreateEBusSenderMimeEvent::m_busName) ->Field("EventName", &CreateEBusSenderMimeEvent::m_eventName) ->Field("IsOverload", &CreateEBusSenderMimeEvent::m_isOverload) + ->Field("propertyStatus", &CreateEBusSenderMimeEvent::m_propertyStatus) ; } } - CreateEBusSenderMimeEvent::CreateEBusSenderMimeEvent(AZStd::string_view busName, AZStd::string_view eventName, bool isOverload) + CreateEBusSenderMimeEvent::CreateEBusSenderMimeEvent(AZStd::string_view busName, AZStd::string_view eventName, bool isOverload, ScriptCanvas::PropertyStatus propertyStatus) : m_busName(busName.data()) , m_eventName(eventName.data()) , m_isOverload(isOverload) + , m_propertyStatus(propertyStatus) { } @@ -71,7 +73,7 @@ namespace ScriptCanvasEditor } else { - return Nodes::CreateObjectMethodNode(m_busName, m_eventName, scriptCanvasId); + return Nodes::CreateObjectMethodNode(m_busName, m_eventName, scriptCanvasId, m_propertyStatus); } } @@ -91,13 +93,14 @@ namespace ScriptCanvasEditor return defaultIcon; } - EBusSendEventPaletteTreeItem::EBusSendEventPaletteTreeItem(AZStd::string_view busName, AZStd::string_view eventName, const ScriptCanvas::EBusBusId& busIdentifier, const ScriptCanvas::EBusEventId& eventIdentifier, bool isOverload) + EBusSendEventPaletteTreeItem::EBusSendEventPaletteTreeItem(AZStd::string_view busName, AZStd::string_view eventName, const ScriptCanvas::EBusBusId& busIdentifier, const ScriptCanvas::EBusEventId& eventIdentifier, bool isOverload, ScriptCanvas::PropertyStatus propertyStatus) : DraggableNodePaletteTreeItem(eventName, ScriptCanvasEditor::AssetEditorId) , m_busName(busName.data()) , m_eventName(eventName.data()) , m_busId(busIdentifier) , m_eventId(eventIdentifier) , m_isOverload(isOverload) + , m_propertyStatus(propertyStatus) { AZStd::string displayEventName = TranslationHelper::GetKeyTranslation(TranslationContextGroup::EbusSender, m_busName.toUtf8().data(), m_eventName.toUtf8().data(), TranslationItemType::Node, TranslationKeyId::Name); @@ -122,7 +125,7 @@ namespace ScriptCanvasEditor GraphCanvas::GraphCanvasMimeEvent* EBusSendEventPaletteTreeItem::CreateMimeEvent() const { - return aznew CreateEBusSenderMimeEvent(m_busName.toUtf8().data(), m_eventName.toUtf8().data(), m_isOverload); + return aznew CreateEBusSenderMimeEvent(m_busName.toUtf8().data(), m_eventName.toUtf8().data(), m_isOverload, ScriptCanvas::PropertyStatus::None); } AZStd::string EBusSendEventPaletteTreeItem::GetBusName() const @@ -145,6 +148,11 @@ namespace ScriptCanvasEditor return m_eventId; } + ScriptCanvas::PropertyStatus EBusSendEventPaletteTreeItem::GetPropertyStatus() const + { + return m_propertyStatus; + } + bool EBusSendEventPaletteTreeItem::IsOverload() const { return m_isOverload; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/EBusNodePaletteTreeItemTypes.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/EBusNodePaletteTreeItemTypes.h index b5181754c4..b3bd771109 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/EBusNodePaletteTreeItemTypes.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/EBusNodePaletteTreeItemTypes.h @@ -28,7 +28,7 @@ namespace ScriptCanvasEditor static void Reflect(AZ::ReflectContext* reflectContext); CreateEBusSenderMimeEvent() = default; - CreateEBusSenderMimeEvent(AZStd::string_view busName, AZStd::string_view eventName, bool isOverload); + CreateEBusSenderMimeEvent(AZStd::string_view busName, AZStd::string_view eventName, bool isOverload, ScriptCanvas::PropertyStatus propertyStatus); ~CreateEBusSenderMimeEvent() = default; protected: @@ -36,6 +36,7 @@ namespace ScriptCanvasEditor private: bool m_isOverload; + ScriptCanvas::PropertyStatus m_propertyStatus = ScriptCanvas::PropertyStatus::None; AZStd::string m_busName; AZStd::string m_eventName; }; @@ -50,7 +51,7 @@ namespace ScriptCanvasEditor AZ_CLASS_ALLOCATOR(EBusSendEventPaletteTreeItem, AZ::SystemAllocator, 0); AZ_RTTI(EBusSendEventPaletteTreeItem, "{26258B0A-8E2C-434D-ACAD-3DE85E64A4F8}", GraphCanvas::DraggableNodePaletteTreeItem); - EBusSendEventPaletteTreeItem(AZStd::string_view busName, AZStd::string_view eventName, const ScriptCanvas::EBusBusId& busId, const ScriptCanvas::EBusEventId& eventIdentifier, bool isOverload); + EBusSendEventPaletteTreeItem(AZStd::string_view busName, AZStd::string_view eventName, const ScriptCanvas::EBusBusId& busId, const ScriptCanvas::EBusEventId& eventIdentifier, bool isOverload, ScriptCanvas::PropertyStatus propertyStatus); ~EBusSendEventPaletteTreeItem() = default; GraphCanvas::GraphCanvasMimeEvent* CreateMimeEvent() const override; @@ -63,6 +64,8 @@ namespace ScriptCanvasEditor bool IsOverload() const; + ScriptCanvas::PropertyStatus GetPropertyStatus() const; + private: bool m_isOverload; QString m_busName; @@ -70,6 +73,7 @@ namespace ScriptCanvasEditor ScriptCanvas::EBusBusId m_busId; ScriptCanvas::EBusEventId m_eventId; + ScriptCanvas::PropertyStatus m_propertyStatus = ScriptCanvas::PropertyStatus::None; }; // diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/GeneralNodePaletteTreeItemTypes.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/GeneralNodePaletteTreeItemTypes.cpp index 912a76df22..8341303ff4 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/GeneralNodePaletteTreeItemTypes.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/GeneralNodePaletteTreeItemTypes.cpp @@ -51,14 +51,16 @@ namespace ScriptCanvasEditor ->Field("ClassName", &CreateClassMethodMimeEvent::m_className) ->Field("MethodName", &CreateClassMethodMimeEvent::m_methodName) ->Field("IsOverload", &CreateClassMethodMimeEvent::m_isOverload) + ->Field("propertyStatus", &CreateClassMethodMimeEvent::m_propertyStatus) ; } } - CreateClassMethodMimeEvent::CreateClassMethodMimeEvent(const QString& className, const QString& methodName, bool isOverload) + CreateClassMethodMimeEvent::CreateClassMethodMimeEvent(const QString& className, const QString& methodName, bool isOverload, ScriptCanvas::PropertyStatus propertyStatus) : m_className(className.toUtf8().data()) , m_methodName(methodName.toUtf8().data()) , m_isOverload(isOverload) + , m_propertyStatus(propertyStatus) { } @@ -70,7 +72,7 @@ namespace ScriptCanvasEditor } else { - return Nodes::CreateObjectMethodNode(m_className, m_methodName, scriptCanvasId); + return Nodes::CreateObjectMethodNode(m_className, m_methodName, scriptCanvasId, m_propertyStatus); } } @@ -78,11 +80,12 @@ namespace ScriptCanvasEditor // ClassMethodEventPaletteTreeItem //////////////////////////////////// - ClassMethodEventPaletteTreeItem::ClassMethodEventPaletteTreeItem(AZStd::string_view className, AZStd::string_view methodName, bool isOverload) + ClassMethodEventPaletteTreeItem::ClassMethodEventPaletteTreeItem(AZStd::string_view className, AZStd::string_view methodName, bool isOverload, ScriptCanvas::PropertyStatus propertyStatus) : DraggableNodePaletteTreeItem(methodName, ScriptCanvasEditor::AssetEditorId) , m_className(className.data()) , m_methodName(methodName.data()) , m_isOverload(isOverload) + , m_propertyStatus(propertyStatus) { AZStd::string displayMethodName = TranslationHelper::GetKeyTranslation(TranslationContextGroup::ClassMethod, m_className.toUtf8().data(), m_methodName.toUtf8().data(), TranslationItemType::Node, TranslationKeyId::Name); @@ -95,6 +98,15 @@ namespace ScriptCanvasEditor SetName(displayMethodName.c_str()); } + if (propertyStatus == ScriptCanvas::PropertyStatus::Getter) + { + SetName(AZStd::string::format("Get %s", GetName().toUtf8().data()).data()); + } + else if (propertyStatus == ScriptCanvas::PropertyStatus::Setter) + { + SetName(AZStd::string::format("Set %s", GetName().toUtf8().data()).data()); + } + AZStd::string displayEventTooltip = TranslationHelper::GetKeyTranslation(TranslationContextGroup::ClassMethod, m_className.toUtf8().data(), m_methodName.toUtf8().data(), TranslationItemType::Node, TranslationKeyId::Tooltip); if (!displayEventTooltip.empty()) @@ -107,7 +119,7 @@ namespace ScriptCanvasEditor GraphCanvas::GraphCanvasMimeEvent* ClassMethodEventPaletteTreeItem::CreateMimeEvent() const { - return aznew CreateClassMethodMimeEvent(m_className, m_methodName, m_isOverload); + return aznew CreateClassMethodMimeEvent(m_className, m_methodName, m_isOverload, m_propertyStatus); } AZStd::string ClassMethodEventPaletteTreeItem::GetClassMethodName() const @@ -125,6 +137,11 @@ namespace ScriptCanvasEditor return m_isOverload; } + ScriptCanvas::PropertyStatus ClassMethodEventPaletteTreeItem::GetPropertyStatus() const + { + return m_propertyStatus; + } + //! Implementation of the CreateGlobalMethod Mime Event void CreateGlobalMethodMimeEvent::Reflect(AZ::ReflectContext* reflectContext) { diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/GeneralNodePaletteTreeItemTypes.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/GeneralNodePaletteTreeItemTypes.h index 38a2be88f5..66b29ef3b9 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/GeneralNodePaletteTreeItemTypes.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/GeneralNodePaletteTreeItemTypes.h @@ -30,7 +30,7 @@ namespace ScriptCanvasEditor static void Reflect(AZ::ReflectContext* reflectContext); CreateClassMethodMimeEvent() = default; - CreateClassMethodMimeEvent(const QString& className, const QString& methodName, bool isOverload); + CreateClassMethodMimeEvent(const QString& className, const QString& methodName, bool isOverload, ScriptCanvas::PropertyStatus); ~CreateClassMethodMimeEvent() = default; protected: @@ -40,6 +40,7 @@ namespace ScriptCanvasEditor bool m_isOverload = false; AZStd::string m_className; AZStd::string m_methodName; + ScriptCanvas::PropertyStatus m_propertyStatus = ScriptCanvas::PropertyStatus::None; }; class ClassMethodEventPaletteTreeItem @@ -49,7 +50,7 @@ namespace ScriptCanvasEditor AZ_CLASS_ALLOCATOR(ClassMethodEventPaletteTreeItem, AZ::SystemAllocator, 0); AZ_RTTI(ClassMethodEventPaletteTreeItem, "{96F93970-F38A-4F08-8DC5-D52FCCE34E25}", GraphCanvas::DraggableNodePaletteTreeItem); - ClassMethodEventPaletteTreeItem(AZStd::string_view className, AZStd::string_view methodName, bool isOverload); + ClassMethodEventPaletteTreeItem(AZStd::string_view className, AZStd::string_view methodName, bool isOverload, ScriptCanvas::PropertyStatus propertyStatus); ~ClassMethodEventPaletteTreeItem() = default; GraphCanvas::GraphCanvasMimeEvent* CreateMimeEvent() const override; @@ -57,11 +58,13 @@ namespace ScriptCanvasEditor AZStd::string GetClassMethodName() const; AZStd::string GetMethodName() const; bool IsOverload() const; + ScriptCanvas::PropertyStatus GetPropertyStatus() const; private: bool m_isOverload = false; QString m_className; QString m_methodName; + ScriptCanvas::PropertyStatus m_propertyStatus = ScriptCanvas::PropertyStatus::None; }; // diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.cpp index 73b6551e85..8b00b5b71b 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.cpp @@ -129,6 +129,7 @@ namespace , const AZ::BehaviorClass* behaviorClass , const AZStd::string& name , const AZ::BehaviorMethod& method + , ScriptCanvas::PropertyStatus propertyStatus , bool isOverloaded) { if (IsDeprecated(method.m_attributes)) @@ -170,7 +171,7 @@ namespace serializeContext->RegisterType(resultParameter->m_typeId, AZStd::move(classData), EventPlaceholderAnyCreator); } - nodePaletteModel.RegisterClassNode(categoryPath, behaviorClass ? behaviorClass->m_name : "", name, &method, &behaviorContext, isOverloaded); + nodePaletteModel.RegisterClassNode(categoryPath, behaviorClass ? behaviorClass->m_name : "", name, &method, &behaviorContext, propertyStatus, isOverloaded); } void RegisterGlobalMethod(ScriptCanvasEditor::NodePaletteModel& nodePaletteModel, const AZ::BehaviorContext& behaviorContext, @@ -556,6 +557,19 @@ namespace categoryPath.append(displayName.c_str()); } + for (auto property : behaviorClass->m_properties) + { + if (property.second->m_getter) + { + RegisterMethod(nodePaletteModel, behaviorContext, categoryPath, behaviorClass, property.first, *property.second->m_getter, ScriptCanvas::PropertyStatus::Getter, behaviorClass->IsMethodOverloaded(property.first)); + } + + if (property.second->m_setter) + { + RegisterMethod(nodePaletteModel, behaviorContext, categoryPath, behaviorClass, property.first, *property.second->m_setter, ScriptCanvas::PropertyStatus::Setter, behaviorClass->IsMethodOverloaded(property.first)); + } + } + for (auto methodIter : behaviorClass->m_methods) { if (!IsExplicitOverload(*methodIter.second)) @@ -567,7 +581,7 @@ namespace continue; } - RegisterMethod(nodePaletteModel, behaviorContext, categoryPath, behaviorClass, methodIter.first, *methodIter.second, behaviorClass->IsMethodOverloaded(methodIter.first)); + RegisterMethod(nodePaletteModel, behaviorContext, categoryPath, behaviorClass, methodIter.first, *methodIter.second, ScriptCanvas::PropertyStatus::None, behaviorClass->IsMethodOverloaded(methodIter.first)); } } } @@ -579,7 +593,7 @@ namespace { for (const AZ::ExplicitOverloadInfo& explicitOverload : behaviorContext.m_explicitOverloads) { - RegisterMethod(nodePaletteModel, behaviorContext, explicitOverload.m_categoryPath, nullptr, explicitOverload.m_name, *explicitOverload.m_overloads.begin()->first, true); + RegisterMethod(nodePaletteModel, behaviorContext, explicitOverload.m_categoryPath, nullptr, explicitOverload.m_name, *explicitOverload.m_overloads.begin()->first, ScriptCanvas::PropertyStatus::None, true); } } @@ -717,7 +731,7 @@ namespace } const bool isOverload{ false }; // overloaded events are not trivially supported - nodePaletteModel.RegisterEBusSenderNodeModelInformation(categoryPath, behaviorEbus.m_name, event.first, ScriptCanvas::EBusBusId(behaviorEbus.m_name.c_str()), ScriptCanvas::EBusEventId(event.first.c_str()), event.second, isOverload); + nodePaletteModel.RegisterEBusSenderNodeModelInformation(categoryPath, behaviorEbus.m_name, event.first, ScriptCanvas::EBusBusId(behaviorEbus.m_name.c_str()), ScriptCanvas::EBusEventId(event.first.c_str()), event.second, ScriptCanvas::PropertyStatus::None, isOverload); } } } @@ -1024,11 +1038,16 @@ namespace ScriptCanvasEditor } } - void NodePaletteModel::RegisterClassNode(const AZStd::string& categoryPath, const AZStd::string& methodClass, - const AZStd::string& methodName, const AZ::BehaviorMethod* behaviorMethod, const AZ::BehaviorContext* behaviorContext, - bool isOverload) + void NodePaletteModel::RegisterClassNode + ( const AZStd::string& categoryPath + , const AZStd::string& methodClass + , const AZStd::string& methodName + , const AZ::BehaviorMethod* behaviorMethod + , const AZ::BehaviorContext* behaviorContext + , ScriptCanvas::PropertyStatus propertyStatus + , bool isOverload) { - ScriptCanvas::NodeTypeIdentifier nodeIdentifier = isOverload ? ScriptCanvas::NodeUtils::ConstructMethodOverloadedNodeIdentifier(methodName) : ScriptCanvas::NodeUtils::ConstructMethodNodeIdentifier(methodClass, methodName); + ScriptCanvas::NodeTypeIdentifier nodeIdentifier = isOverload ? ScriptCanvas::NodeUtils::ConstructMethodOverloadedNodeIdentifier(methodName) : ScriptCanvas::NodeUtils::ConstructMethodNodeIdentifier(methodClass, methodName, propertyStatus); auto registerIter = m_registeredNodes.find(nodeIdentifier); @@ -1039,7 +1058,7 @@ namespace ScriptCanvasEditor methodModelInformation->m_nodeIdentifier = nodeIdentifier; methodModelInformation->m_classMethod = methodClass; methodModelInformation->m_methodName = methodName; - + methodModelInformation->m_propertyStatus = propertyStatus; methodModelInformation->m_titlePaletteOverride = "MethodNodeTitlePalette"; methodModelInformation->m_displayName = TranslationHelper::GetKeyTranslation(TranslationContextGroup::ClassMethod, methodClass.c_str(), methodName.c_str(), TranslationItemType::Node, TranslationKeyId::Name); @@ -1198,7 +1217,15 @@ namespace ScriptCanvasEditor } } - void NodePaletteModel::RegisterEBusSenderNodeModelInformation(AZStd::string_view categoryPath, AZStd::string_view busName, AZStd::string_view eventName, const ScriptCanvas::EBusBusId& busId, const ScriptCanvas::EBusEventId& eventId, const AZ::BehaviorEBusEventSender&, bool isOverload) + void NodePaletteModel::RegisterEBusSenderNodeModelInformation + ( AZStd::string_view categoryPath + , AZStd::string_view busName + , AZStd::string_view eventName + , const ScriptCanvas::EBusBusId& busId + , const ScriptCanvas::EBusEventId& eventId + , const AZ::BehaviorEBusEventSender& + , ScriptCanvas::PropertyStatus propertyStatus + , bool isOverload) { ScriptCanvas::NodeTypeIdentifier nodeIdentifier = isOverload ? ScriptCanvas::NodeUtils::ConstructEBusEventSenderOverloadedIdentifier(busId, eventId) : ScriptCanvas::NodeUtils::ConstructEBusEventSenderIdentifier(busId, eventId); @@ -1212,6 +1239,7 @@ namespace ScriptCanvasEditor senderInformation->m_titlePaletteOverride = "MethodNodeTitlePalette"; senderInformation->m_categoryPath = categoryPath; senderInformation->m_nodeIdentifier = nodeIdentifier; + senderInformation->m_propertyStatus = propertyStatus; senderInformation->m_busName = busName; senderInformation->m_eventName = eventName; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.h index 5ed0ff670b..3bc81c07a0 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.h @@ -83,12 +83,12 @@ namespace ScriptCanvasEditor void RepopulateModel(); void RegisterCustomNode(AZStd::string_view categoryPath, const AZ::Uuid& uuid, AZStd::string_view name, const AZ::SerializeContext::ClassData* classData); - void RegisterClassNode(const AZStd::string& categoryPath, const AZStd::string& methodClass, const AZStd::string& methodName, const AZ::BehaviorMethod* behaviorMethod, const AZ::BehaviorContext* behaviorContext, bool isOverload); + void RegisterClassNode(const AZStd::string& categoryPath, const AZStd::string& methodClass, const AZStd::string& methodName, const AZ::BehaviorMethod* behaviorMethod, const AZ::BehaviorContext* behaviorContext, ScriptCanvas::PropertyStatus propertyStatus, bool isOverload); void RegisterMethodNode(const AZ::BehaviorContext& behaviorContext, const AZ::BehaviorMethod& behaviorMethod); void RegisterGlobalConstant(const AZ::BehaviorContext& behaviorContext, const AZ::BehaviorMethod& behaviorMethod); void RegisterEBusHandlerNodeModelInformation(AZStd::string_view categoryPath, AZStd::string_view busName, AZStd::string_view eventName, const ScriptCanvas::EBusBusId& busId, const AZ::BehaviorEBusHandler::BusForwarderEvent& forwardEvent); - void RegisterEBusSenderNodeModelInformation(AZStd::string_view categoryPath, AZStd::string_view busName, AZStd::string_view eventName, const ScriptCanvas::EBusBusId& busId, const ScriptCanvas::EBusEventId& eventId, const AZ::BehaviorEBusEventSender& eventSender, bool isOverload); + void RegisterEBusSenderNodeModelInformation(AZStd::string_view categoryPath, AZStd::string_view busName, AZStd::string_view eventName, const ScriptCanvas::EBusBusId& busId, const ScriptCanvas::EBusEventId& eventId, const AZ::BehaviorEBusEventSender& eventSender, ScriptCanvas::PropertyStatus propertyStatus, bool isOverload); // Asset Based Registrations AZStd::vector RegisterScriptEvent(ScriptEvents::ScriptEventsAsset* scriptEventAsset); @@ -164,6 +164,7 @@ namespace ScriptCanvasEditor bool m_isOverload{}; AZStd::string m_classMethod; AZStd::string m_methodName; + ScriptCanvas::PropertyStatus m_propertyStatus = ScriptCanvas::PropertyStatus::None; }; struct GlobalMethodNodeModelInformation @@ -202,6 +203,7 @@ namespace ScriptCanvasEditor ScriptCanvas::EBusBusId m_busId; ScriptCanvas::EBusEventId m_eventId; + ScriptCanvas::PropertyStatus m_propertyStatus = ScriptCanvas::PropertyStatus::None; }; struct ScriptEventHandlerNodeModelInformation diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp index 5d377fe241..062db5e315 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp @@ -111,7 +111,7 @@ namespace ScriptCanvasEditor } else if (auto methodNodeModelInformation = azrtti_cast(modelInformation)) { - createdItem = parentItem->CreateChildNode(methodNodeModelInformation->m_classMethod, methodNodeModelInformation->m_methodName, methodNodeModelInformation->m_isOverload); + createdItem = parentItem->CreateChildNode(methodNodeModelInformation->m_classMethod, methodNodeModelInformation->m_methodName, methodNodeModelInformation->m_isOverload, methodNodeModelInformation->m_propertyStatus); } else if (auto globalMethodNodeModelInformation = azrtti_cast(modelInformation); globalMethodNodeModelInformation != nullptr) @@ -130,7 +130,7 @@ namespace ScriptCanvasEditor { if (!azrtti_istypeof(ebusSenderNodeModelInformation)) { - createdItem = parentItem->CreateChildNode(ebusSenderNodeModelInformation->m_busName, ebusSenderNodeModelInformation->m_eventName, ebusSenderNodeModelInformation->m_busId, ebusSenderNodeModelInformation->m_eventId, ebusSenderNodeModelInformation->m_isOverload); + createdItem = parentItem->CreateChildNode(ebusSenderNodeModelInformation->m_busName, ebusSenderNodeModelInformation->m_eventName, ebusSenderNodeModelInformation->m_busId, ebusSenderNodeModelInformation->m_eventId, ebusSenderNodeModelInformation->m_isOverload, ebusSenderNodeModelInformation->m_propertyStatus); } } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h index d6ac7e5482..5b1e5eee76 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h @@ -88,6 +88,13 @@ namespace ScriptCanvas Current, }; + enum class PropertyStatus : AZ::u8 + { + Getter, + None, + Setter, + }; + struct VersionData { AZ_TYPE_INFO(VersionData, "{14C629F6-467B-46FE-8B63-48FDFCA42175}"); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/MethodConfiguration.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/MethodConfiguration.h index be1f4b39b8..049404ee6e 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/MethodConfiguration.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/MethodConfiguration.h @@ -33,6 +33,8 @@ namespace ScriptCanvas Event, Free, Member, + Getter, + Setter, Count, }; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h index d3d36ae71b..a2d06686e9 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h @@ -394,6 +394,7 @@ namespace ScriptCanvas AZ::Uuid m_type = AZ::Uuid::CreateNull(); AZStd::string m_className; AZStd::string m_methodName; + PropertyStatus m_propertyStatus = PropertyStatus::None; bool IsValid() { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp index b642ef3889..83680aa7de 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp @@ -104,8 +104,7 @@ namespace ScriptCanvas const FunctorOut& Nodeable::GetExecutionOutChecked(size_t index) const { - - if (index >= m_outs.size() && m_outs[index]) + if (index >= m_outs.size() || !m_outs[index]) { return m_noOpFunctor; } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingUtilities.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingUtilities.cpp index a5a98b5444..e16a3bc815 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingUtilities.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingUtilities.cpp @@ -537,6 +537,20 @@ namespace ScriptCanvas return azrtti_istypeof(execution->GetId().m_node); } + bool IsClassPropertyRead(ExecutionTreeConstPtr execution) + { + return execution->GetSymbol() == Symbol::FunctionCall + && azrtti_istypeof(execution->GetId().m_node) + && azrtti_cast(execution->GetId().m_node)->GetPropertyStatus() == PropertyStatus::Getter; + } + + bool IsClassPropertyWrite(ExecutionTreeConstPtr execution) + { + return execution->GetSymbol() == Symbol::FunctionCall + && azrtti_istypeof(execution->GetId().m_node) + && azrtti_cast(execution->GetId().m_node)->GetPropertyStatus() == PropertyStatus::Setter; + } + bool IsCodeConstructable(Grammar::VariableConstPtr value) { return Data::IsValueType(value->m_datum.GetType()) @@ -1280,7 +1294,6 @@ namespace ScriptCanvas return identifier; } - ExecutionTraversalResult TraverseExecutionConnectionsRecurse(const EndpointsResolved& nextEndpoints, AZStd::unordered_set& previousIns, GraphExecutionPathTraversalListener& listener); ExecutionTraversalResult TraverseExecutionConnectionsRecurse(const EndpointResolved& in, AZStd::unordered_set& previousIns, GraphExecutionPathTraversalListener& listener); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingUtilities.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingUtilities.h index 1e2d102d2d..b5fd606fba 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingUtilities.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingUtilities.h @@ -79,6 +79,10 @@ namespace ScriptCanvas bool IsBreak(const ExecutionTreeConstPtr& execution); + bool IsClassPropertyRead(ExecutionTreeConstPtr execution); + + bool IsClassPropertyWrite(ExecutionTreeConstPtr execution); + bool IsCodeConstructable(VariableConstPtr value); bool IsCycle(const Node& node); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.cpp index 836c3facab..b6f7bc2972 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.cpp @@ -193,6 +193,22 @@ namespace ScriptCanvas return DynamicDataType::Any; } + PropertyStatus Method::GetPropertyStatus() const + { + switch (m_methodType) + { + case MethodType::Getter: + return PropertyStatus::Getter; + + case MethodType::Setter: + return PropertyStatus::Setter; + + default: + return PropertyStatus::None; + } + } + + void Method::InitializeMethod(const MethodConfiguration& config) { m_namespaces = config.m_namespaces ? *config.m_namespaces : m_namespaces; @@ -239,7 +255,7 @@ namespace ScriptCanvas OnInitializeOutputPost(outputConfig); } - void Method::InitializeBehaviorMethod(const NamespacePath& namespaces, AZStd::string_view className, AZStd::string_view methodName) + void Method::InitializeBehaviorMethod(const NamespacePath& namespaces, AZStd::string_view className, AZStd::string_view methodName, PropertyStatus propertyStatus) { AZ::BehaviorContext* behaviorContext = nullptr; AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationRequests::GetBehaviorContext); @@ -255,13 +271,13 @@ namespace ScriptCanvas { InitializeFree(namespaces, methodName); } - else if (auto ebusIterator = behaviorContext->m_ebuses.find(className); ebusIterator == behaviorContext->m_ebuses.end()) + else if (auto ebusIterator = behaviorContext->m_ebuses.find(className); ebusIterator != behaviorContext->m_ebuses.end()) { - InitializeClass(namespaces, className, methodName); + InitializeEvent(namespaces, className, methodName); } else { - InitializeEvent(namespaces, className, methodName); + InitializeClass(namespaces, className, methodName, propertyStatus); } } @@ -291,7 +307,7 @@ namespace ScriptCanvas } } - void Method::InitializeClass(const NamespacePath&, AZStd::string_view className, AZStd::string_view methodName) + void Method::InitializeClass(const NamespacePath&, AZStd::string_view className, AZStd::string_view methodName, PropertyStatus propertyStatus) { AZStd::lock_guard lock(m_mutex); @@ -299,9 +315,11 @@ namespace ScriptCanvas const AZ::BehaviorClass* bcClass{}; AZStd::string prettyClassName; - if (BehaviorContextUtils::FindClass(method, bcClass, className, methodName, &prettyClassName)) + if (BehaviorContextUtils::FindClass(method, bcClass, className, methodName, propertyStatus, &prettyClassName)) { - MethodConfiguration config(*method, MethodType::Member); + const auto methodType = propertyStatus == PropertyStatus::None ? MethodType::Member : propertyStatus == PropertyStatus::Getter ? MethodType::Getter : MethodType::Setter; + + MethodConfiguration config(*method, methodType); config.m_class = bcClass; config.m_namespaces = &m_namespaces; config.m_className = &className; @@ -647,8 +665,12 @@ namespace ScriptCanvas break; case MethodType::Member: + case MethodType::Getter: + case MethodType::Setter: { - if (BehaviorContextUtils::FindClass(method, bcClass, m_className, methodName, nullptr, m_warnOnMissingFunction)) + PropertyStatus status = m_methodType == MethodType::Getter ? PropertyStatus::Getter : m_methodType == MethodType::Setter ? PropertyStatus::Setter : PropertyStatus::None; + + if (BehaviorContextUtils::FindClass(method, bcClass, m_className, methodName, status, nullptr, m_warnOnMissingFunction)) { outClass = bcClass; outMethod = method; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.h index b03e3aefd8..6a53054ddf 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.h @@ -87,14 +87,13 @@ namespace ScriptCanvas bool IsObjectClass(AZStd::string_view objectClass) const { return objectClass.compare(m_className) == 0; } //! Attempts to initialize node with a BehaviorContext BehaviorMethod - //! If the className is empty, then the methodName is searched on the BehaviorContext - //! If className is not empty the className is used to look for a registered BehaviorEBus in the BehaviorContext - //! and if found, the methodName is searched among the BehaviorEBus events - //! Otherwise the className is used to look for a registered BehaviorClass in the BehaviorContext - //! and if found, the methodName is searched among the BehaviorClass methods - void InitializeBehaviorMethod(const NamespacePath& namespaces, AZStd::string_view className, AZStd::string_view methodName); + //! 1) If the names match an overloaded method, including one using ExplicitOverloadInfo, then that method is used. Else: + //! 2) If the class name is empty, then search for a free method is searched for in the BehaviorContext and there is a warning if not found. + //! 3) If the class name matches an ebus, methodName is searched among the BehaviorEBus events, and there is a warning if not found. + //! 4) if the class name does NOT match an ebus, className and methodName are used to look for a registered BehaviorClass in the BehaviorContext, and there is a warning if not found. + void InitializeBehaviorMethod(const NamespacePath& namespaces, AZStd::string_view className, AZStd::string_view methodName, PropertyStatus propertyStatus); - void InitializeClass(const NamespacePath& namespaces, AZStd::string_view className, AZStd::string_view methodName); + void InitializeClass(const NamespacePath& namespaces, AZStd::string_view className, AZStd::string_view methodName, PropertyStatus propertyStatus); void InitializeEvent(const NamespacePath& namespaces, AZStd::string_view busName, AZStd::string_view eventName); @@ -126,6 +125,8 @@ namespace ScriptCanvas virtual DynamicDataType GetOverloadedOutputType(size_t resultIndex) const; + PropertyStatus GetPropertyStatus() const; + protected: void ConfigureMethod(const AZ::BehaviorMethod& method, const AZ::BehaviorClass* bcClass); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.cpp index 128ef95b63..905f68604a 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.cpp @@ -637,6 +637,16 @@ namespace ScriptCanvas { WriteGlobalPropertyRead(execution); } + else if (Grammar::IsClassPropertyRead(execution)) + { + WriteClassPropertyRead(execution); + m_dotLua.WriteNewLine(); + } + else if (Grammar::IsClassPropertyWrite(execution)) + { + WriteClassPropertyWrite(execution); + m_dotLua.WriteNewLine(); + } else { const bool isNullCheckRequired = Grammar::IsFunctionCallNullCheckRequired(execution); @@ -1208,6 +1218,19 @@ namespace ScriptCanvas TranslateNodeableParse(); } + void GraphToLua::WriteClassPropertyRead(Grammar::ExecutionTreeConstPtr execution) + { + WriteFunctionCallInput(execution, 0, IsFormatStringInput::No); + m_dotLua.Write(".%s", Grammar::ToIdentifier(execution->GetName()).c_str()); + } + + void GraphToLua::WriteClassPropertyWrite(Grammar::ExecutionTreeConstPtr execution) + { + WriteClassPropertyRead(execution); + m_dotLua.Write(" = "); + WriteFunctionCallInput(execution, 1, IsFormatStringInput::No); + } + void GraphToLua::WriteConditionalCaseSwitch(Grammar::ExecutionTreeConstPtr execution, Grammar::Symbol symbol, const Grammar::ExecutionChild& child, size_t index) { if (symbol == Grammar::Symbol::RandomSwitch) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.h index 3d4379d98d..82c865da8c 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.h @@ -116,6 +116,8 @@ namespace ScriptCanvas void TranslateNodeableParse(); void TranslateStaticInitialization(); void TranslateVariableInitialization(AZStd::string_view leftValue); + void WriteClassPropertyRead(Grammar::ExecutionTreeConstPtr); + void WriteClassPropertyWrite(Grammar::ExecutionTreeConstPtr); void WriteConditionalCaseSwitch(Grammar::ExecutionTreeConstPtr execution, Grammar::Symbol symbol, const Grammar::ExecutionChild& child, size_t index); enum class IsLeadingCommaRequired { No, Yes }; void WriteConstructionArgs(); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/BehaviorContextUtils.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/BehaviorContextUtils.cpp index ff38b74d47..3689729338 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/BehaviorContextUtils.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/BehaviorContextUtils.cpp @@ -61,7 +61,7 @@ namespace ScriptCanvas return { typeID }; } - bool BehaviorContextUtils::FindClass(const AZ::BehaviorMethod*& outMethod, const AZ::BehaviorClass*& outClass, [[maybe_unused]] AZStd::string_view className, [[maybe_unused]] AZStd::string_view methodName, [[maybe_unused]] AZStd::string* outPrettyClassName, [[maybe_unused]] bool warnOnMissing) + bool BehaviorContextUtils::FindClass(const AZ::BehaviorMethod*& outMethod, const AZ::BehaviorClass*& outClass, [[maybe_unused]] AZStd::string_view className, [[maybe_unused]] AZStd::string_view methodName, PropertyStatus propertyStatus, [[maybe_unused]] AZStd::string* outPrettyClassName, [[maybe_unused]] bool warnOnMissing) { AZ::BehaviorContext* behaviorContext(nullptr); AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationRequests::GetBehaviorContext); @@ -81,16 +81,36 @@ namespace ScriptCanvas const AZ::BehaviorClass* behaviorClass(classIter->second); AZ_Assert(behaviorClass, "BehaviorContext Class entry %s has no class pointer", className.data()); - const auto methodIter(behaviorClass->m_methods.find(methodName.data())); - if (methodIter == behaviorClass->m_methods.end()) + + AZ::BehaviorMethod* method{}; + + if (propertyStatus == PropertyStatus::None) { - AZ_Warning("Script Canvas", !warnOnMissing, "No method by name of %s found in BehaviorContext class %s", methodName.data(), className.data()); - return false; + const auto methodIter(behaviorClass->m_methods.find(methodName.data())); + if (methodIter != behaviorClass->m_methods.end()) + { + method = methodIter->second; + propertyStatus = PropertyStatus::None; + } + else + { + AZ_Warning("Script Canvas", !warnOnMissing, "No method by name of %s found in BehaviorContext class %s", methodName.data(), className.data()); + } + } + else + { + const auto propertyIter(behaviorClass->m_properties.find(methodName.data())); + if (propertyIter == behaviorClass->m_properties.end()) + { + AZ_Warning("Script Canvas", !warnOnMissing, "No property by name of %s found in BehaviorContext class %s", methodName.data(), className.data()); + return false; + } + + method = propertyStatus == PropertyStatus::Getter ? propertyIter->second->m_getter : propertyIter->second->m_setter; } // this argument is the first argument...so perhaps remove the distinction between class and member functions, since it probably won't follow polymorphism // if it will, keep the distinction, and add the first argument separately - AZ::BehaviorMethod* method(methodIter->second); if (!method) { AZ_Warning("Script Canvas", !warnOnMissing, "BehaviorContext Method entry %s has no method pointer", methodName.data()); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/BehaviorContextUtils.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/BehaviorContextUtils.h index 057c99a774..8abe26dfd1 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/BehaviorContextUtils.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/BehaviorContextUtils.h @@ -21,7 +21,7 @@ namespace ScriptCanvas class BehaviorContextUtils { public: - static bool FindClass(const AZ::BehaviorMethod*& outMethod, const AZ::BehaviorClass*& outClass, AZStd::string_view className, AZStd::string_view methodName, AZStd::string* outPrettyClassName = nullptr, bool warnOnMissing = true); + static bool FindClass(const AZ::BehaviorMethod*& outMethod, const AZ::BehaviorClass*& outClass, AZStd::string_view className, AZStd::string_view methodName, PropertyStatus propertyStatus = PropertyStatus::None, AZStd::string* outPrettyClassName = nullptr, bool warnOnMissing = true); static bool FindEBus(const AZ::BehaviorEBus*& outEBus, AZStd::string_view ebusName, bool warnOnMissing = true); static bool FindExplicitOverload(const AZ::BehaviorMethod*& outMethod, const AZ::BehaviorClass*& outClass, AZStd::string_view className, AZStd::string_view methodName, AZStd::string* outPrettyClassName = nullptr); static AZStd::string FindExposedMethodName(const AZ::BehaviorMethod& method, const AZ::BehaviorClass* behaviorClass); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/NodeUtils.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/NodeUtils.cpp index 06ad79c21d..c6849f0b12 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/NodeUtils.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/NodeUtils.cpp @@ -58,7 +58,7 @@ namespace ScriptCanvas } else { - return ConstructMethodNodeIdentifier(methodNode->GetRawMethodClassName(), methodNode->GetName()); + return ConstructMethodNodeIdentifier(methodNode->GetRawMethodClassName(), methodNode->GetName(), methodNode->GetPropertyStatus()); } } else if (auto ebusNode = azrtti_cast(scriptCanvasNode)) @@ -158,13 +158,14 @@ namespace ScriptCanvas return resultHash; } - NodeTypeIdentifier NodeUtils::ConstructMethodNodeIdentifier(AZStd::string_view methodClass, AZStd::string_view methodName) + NodeTypeIdentifier NodeUtils::ConstructMethodNodeIdentifier(AZStd::string_view methodClass, AZStd::string_view methodName, ScriptCanvas::PropertyStatus propertyStatus) { NodeTypeIdentifier resultHash = 0; AZStd::hash_combine(resultHash, AZStd::hash()(azrtti_typeid())); AZStd::hash_combine(resultHash, AZStd::hash()(methodClass)); AZStd::hash_combine(resultHash, AZStd::hash()(methodName)); + AZStd::hash_combine(resultHash, AZStd::hash()(static_cast(propertyStatus))); return resultHash; } @@ -253,7 +254,7 @@ namespace ScriptCanvas if (auto* method = azrtti_cast(node)) { ScriptCanvas::NamespacePath emptyNamespaces; - method->InitializeBehaviorMethod(emptyNamespaces, config.m_className, config.m_methodName); + method->InitializeBehaviorMethod(emptyNamespaces, config.m_className, config.m_methodName, config.m_propertyStatus); } } } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/NodeUtils.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/NodeUtils.h index 0f5b0f495d..ad8356c42e 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/NodeUtils.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/NodeUtils.h @@ -38,7 +38,7 @@ namespace ScriptCanvas static NodeTypeIdentifier ConstructCustomNodeIdentifier(const AZ::Uuid& nodeId); - static NodeTypeIdentifier ConstructMethodNodeIdentifier(AZStd::string_view methodClass, AZStd::string_view methodName); + static NodeTypeIdentifier ConstructMethodNodeIdentifier(AZStd::string_view methodClass, AZStd::string_view methodName, ScriptCanvas::PropertyStatus propertyStatus); static NodeTypeIdentifier ConstructGlobalMethodNodeIdentifier(AZStd::string_view methodName); static NodeTypeIdentifier ConstructMethodOverloadedNodeIdentifier(AZStd::string_view methodName); diff --git a/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/UnitTests/LY_SC_UnitTest_UseRawBehaviorProperties.scriptcanvas b/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/UnitTests/LY_SC_UnitTest_UseRawBehaviorProperties.scriptcanvas new file mode 100644 index 0000000000..57e57116e0 --- /dev/null +++ b/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/UnitTests/LY_SC_UnitTest_UseRawBehaviorProperties.scriptcanvas @@ -0,0 +1,2618 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h b/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h index 7f026edf58..766353c4c5 100644 --- a/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h +++ b/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h @@ -21,23 +21,24 @@ #include #include #include +#include #include #include #include +#include +#include +#include #include #include #include #include -#include #include "EntityRefTests.h" #include "ScriptCanvasTestApplication.h" #include "ScriptCanvasTestBus.h" #include "ScriptCanvasTestNodes.h" #include "ScriptCanvasTestUtilities.h" -#include -#include #define SC_EXPECT_DOUBLE_EQ(candidate, reference) EXPECT_NEAR(candidate, reference, 0.001) #define SC_EXPECT_FLOAT_EQ(candidate, reference) EXPECT_NEAR(candidate, reference, 0.001f) @@ -112,6 +113,9 @@ namespace ScriptCanvasTests ScriptCanvasTesting::Reflect(m_serializeContext); ScriptCanvasTesting::Reflect(m_behaviorContext); + ScriptCanvasTestingNodes::BehaviorContextObjectTest::Reflect(m_serializeContext); + ScriptCanvasTestingNodes::BehaviorContextObjectTest::Reflect(m_behaviorContext); + ::Nodes::InputMethodSharedDataSlotExampleNode::Reflect(m_serializeContext); ::Nodes::InputMethodSharedDataSlotExampleNode::Reflect(m_behaviorContext); ::Nodes::BranchMethodSharedDataSlotExampleNode::Reflect(m_serializeContext); diff --git a/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestUtilities.cpp b/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestUtilities.cpp index 9fc023601e..bd31edad09 100644 --- a/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestUtilities.cpp +++ b/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestUtilities.cpp @@ -496,7 +496,7 @@ namespace ScriptCanvasTests ScriptCanvas::Nodes::Core::Method* methodNode(nullptr); SystemRequestBus::BroadcastResult(methodNode, &SystemRequests::GetNode, methodNodeID); EXPECT_TRUE(methodNode != nullptr); - methodNode->InitializeBehaviorMethod(emptyNamespaces, className, methodName); + methodNode->InitializeBehaviorMethod(emptyNamespaces, className, methodName, ScriptCanvas::PropertyStatus::None); return methodNodeID; } diff --git a/Gems/ScriptCanvasTesting/Code/Source/Nodes/BehaviorContextObjectTestNode.h b/Gems/ScriptCanvasTesting/Code/Source/Nodes/BehaviorContextObjectTestNode.h index 2460d37c02..7fa3896ff1 100644 --- a/Gems/ScriptCanvasTesting/Code/Source/Nodes/BehaviorContextObjectTestNode.h +++ b/Gems/ScriptCanvasTesting/Code/Source/Nodes/BehaviorContextObjectTestNode.h @@ -30,10 +30,10 @@ namespace ScriptCanvasTestingNodes { serializeContext->Class() ->Version(0) - ->Field("StringName", &BehaviorContextObjectTest::m_string) + ->Field("String", &BehaviorContextObjectTest::m_string) + ->Field("Name", &BehaviorContextObjectTest::m_name) ; - - + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) { editContext->Class("Behavior Context Object Test", "An Object that lives within Behavior Context exclusively for testing") @@ -52,6 +52,7 @@ namespace ScriptCanvasTestingNodes ->Attribute(AZ::Script::Attributes::Category, "Tests/Behavior Context") ->Method("SetString", &BehaviorContextObjectTest::SetString) ->Method("GetString", &BehaviorContextObjectTest::GetString) + ->Property("Name", BehaviorValueProperty(&BehaviorContextObjectTest::m_name)) ; } } @@ -73,7 +74,7 @@ namespace ScriptCanvasTestingNodes } private: - + AZStd::string m_name; AZStd::string m_string; }; diff --git a/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp b/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp index a46bb3323b..1633b0fc51 100644 --- a/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp +++ b/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp @@ -90,6 +90,11 @@ public: } }; +TEST_F(ScriptCanvasTestFixture, UseRawBehaviorProperties) +{ + RunUnitTestGraph("LY_SC_UnitTest_UseRawBehaviorProperties"); +} + TEST_F(ScriptCanvasTestFixture, StringSanitization) { RunUnitTestGraph("LY_SC_UnitTest_StringSanitization");