Merge branch 'main' into SPEC-6690

This commit is contained in:
zsolleci
2021-05-06 14:36:18 -05:00
62 changed files with 3283 additions and 210 deletions
@@ -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<AZ::u64>(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);
}
}
@@ -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<AZ::EntityId, AZ::u64> m_childIndexCache;
@@ -375,6 +373,5 @@ namespace AzToolsFramework
AZ::EntityId m_postInstantiateBeforeEntity;
AZ::EntityId m_postInstantiateSliceParent;
bool m_gotInstantiateSliceDetails = false;
bool m_isPrefabEnabled = false;
};
}
@@ -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();
+1 -1
View File
@@ -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;
@@ -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
@@ -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
@@ -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 <AzCore/Math/Uuid.h>
#include <QString>
#include <QStringList>
#include <QVector>
#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<AZ::Uuid> m_dependingGemUuids;
QVector<AZ::Uuid> m_conflictingGemUuids;
};
} // namespace O3DE::ProjectManager
Q_DECLARE_OPERATORS_FOR_FLAGS(O3DE::ProjectManager::GemInfo::Platforms)
@@ -37,4 +37,6 @@ set(FILES
Source/EngineSettings.h
Source/EngineSettings.cpp
Source/EngineSettings.ui
Source/GemCatalog/GemInfo.h
Source/GemCatalog/GemInfo.cpp
)
@@ -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;
@@ -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",
@@ -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<AZStd::string(const AWSResourceMappingAttributes&)> 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;
@@ -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
@@ -84,7 +84,7 @@ namespace AWSCore
{
AZ_Warning("AWSDefaultCredentialHandler", false, "Failed to get profile name, use default profile name instead");
SetProfileCredentialsProvider(Aws::MakeShared<Aws::Auth::ProfileConfigFileAWSCredentialsProvider>(
AWSDEFAULTCREDENTIALHANDLER_ALLOC_TAG, AWSCoreConfiguration::AWSCORE_DEFAULT_PROFILE_NAME));
AWSDEFAULTCREDENTIALHANDLER_ALLOC_TAG, AWSCoreConfiguration::AWSCoreDefaultProfileName));
}
else
{
@@ -12,12 +12,14 @@
#include <AzCore/IO/Path/Path.h>
#include <AzCore/JSON/schema.h>
#include <AzCore/JSON/prettywriter.h>
#include <AzCore/Settings/SettingsRegistry.h>
#include <AzCore/Settings/SettingsRegistryImpl.h>
#include <AzFramework/FileFunc/FileFunc.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AWSCoreInternalBus.h>
#include <Configuration/AWSCoreConfiguration.h>
#include <ResourceMapping/AWSResourceMappingConstants.h>
#include <ResourceMapping/AWSResourceMappingManager.h>
#include <ResourceMapping/AWSResourceMappingUtils.h>
@@ -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<rapidjson::StringBuffer> writer(error);
validator.GetError().Accept(writer);
AZ_Warning(AWSResourceMappingManagerName, false, ResourceMappingFileInvalidContentErrorMessage, error.GetString());
return false;
}
return true;
@@ -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());
}
}
@@ -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);
}
@@ -98,7 +98,7 @@ public:
"AWSResourceMappingManager", AZ::Uuid::CreateRandom().ToString<AZStd::string>(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);
}
@@ -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;
@@ -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());
@@ -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;
@@ -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());
@@ -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;
@@ -15,6 +15,7 @@
#if !defined(Q_MOC_RUN)
#include <AzCore/Memory/SystemAllocator.h>
#include <AzQtComponents/Components/ExtendedLabel.h>
#include <QMouseEvent>
#include <QPaintEvent>
#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:
@@ -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<InspectorRequests>;
@@ -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<Ui::InspectorWidget> m_ui;
AZStd::vector<InspectorGroupHeaderWidget*> m_headers;
AZStd::vector<QWidget*> m_groups;
};
} // namespace AtomToolsFramework
@@ -14,10 +14,10 @@
#include <AzQtComponents/Components/StyleManager.h>
#include <AzQtComponents/Components/Widgets/Text.h>
#include <QStyle>
#include <QPainter>
#include <QApplication>
#include <QPainter>
#include <QPixmap>
#include <QStyle>
#include <QStyleOptionViewItem>
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
@@ -10,12 +10,13 @@
*
*/
#include <QMenu>
#include <QScrollArea>
#include <QScrollBar>
#include <QSizePolicy>
#include <AtomToolsFramework/Inspector/InspectorGroupWidget.h>
#include <AtomToolsFramework/Inspector/InspectorGroupHeaderWidget.h>
#include <AtomToolsFramework/Inspector/InspectorGroupWidget.h>
#include <AtomToolsFramework/Inspector/InspectorWidget.h>
#include <Source/Inspector/ui_InspectorWidget.h>
@@ -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 <AtomToolsFramework/Inspector/moc_InspectorWidget.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);
}
}
@@ -14,6 +14,7 @@
#include <AzCore/Component/Component.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Component/NonUniformScaleBus.h>
#include <AtomLyIntegration/CommonFeatures/Decals/DecalBus.h>
#include <AtomLyIntegration/CommonFeatures/Decals/DecalComponentConfig.h>
#include <Atom/Feature/Decals/DecalFeatureProcessorInterface.h>
@@ -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
@@ -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)
@@ -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()
@@ -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();
@@ -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<const GlobalMethodEventPaletteTreeItem*>(treeItem); globalMethodTreeItem != nullptr)
@@ -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<ScriptCanvas::Nodes::Core::Method*>(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<int>(displayName.size()), displayName.data()));
@@ -208,7 +208,7 @@ namespace ScriptCanvasEditor::Nodes
auto* methodNode = azrtti_cast<ScriptCanvas::Nodes::Core::MethodOverloaded*>(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<int>(displayName.size()), displayName.data()));
@@ -34,7 +34,7 @@ namespace ScriptCanvasEditor::Nodes
AZStd::pair<ScriptCanvas::Node*, NodeIdPair> CreateAndGetNode(const AZ::Uuid& classData, const ScriptCanvas::ScriptCanvasId& scriptCanvasId, const StyleConfiguration& styleConfiguration, AZStd::function<void(ScriptCanvas::Node*)> = 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);
@@ -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<ClassMethodNodeDescriptorComponent>();
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;
}
@@ -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;
@@ -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;
};
// </EbusSender>
@@ -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)
{
@@ -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;
};
// </ClassMethod>
@@ -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;
@@ -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<ScriptCanvas::NodeTypeIdentifier> 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
@@ -111,7 +111,7 @@ namespace ScriptCanvasEditor
}
else if (auto methodNodeModelInformation = azrtti_cast<const MethodNodeModelInformation*>(modelInformation))
{
createdItem = parentItem->CreateChildNode<ScriptCanvasEditor::ClassMethodEventPaletteTreeItem>(methodNodeModelInformation->m_classMethod, methodNodeModelInformation->m_methodName, methodNodeModelInformation->m_isOverload);
createdItem = parentItem->CreateChildNode<ScriptCanvasEditor::ClassMethodEventPaletteTreeItem>(methodNodeModelInformation->m_classMethod, methodNodeModelInformation->m_methodName, methodNodeModelInformation->m_isOverload, methodNodeModelInformation->m_propertyStatus);
}
else if (auto globalMethodNodeModelInformation = azrtti_cast<const GlobalMethodNodeModelInformation*>(modelInformation);
globalMethodNodeModelInformation != nullptr)
@@ -130,7 +130,7 @@ namespace ScriptCanvasEditor
{
if (!azrtti_istypeof<const ScriptEventSenderNodeModelInformation*>(ebusSenderNodeModelInformation))
{
createdItem = parentItem->CreateChildNode<ScriptCanvasEditor::EBusSendEventPaletteTreeItem>(ebusSenderNodeModelInformation->m_busName, ebusSenderNodeModelInformation->m_eventName, ebusSenderNodeModelInformation->m_busId, ebusSenderNodeModelInformation->m_eventId, ebusSenderNodeModelInformation->m_isOverload);
createdItem = parentItem->CreateChildNode<ScriptCanvasEditor::EBusSendEventPaletteTreeItem>(ebusSenderNodeModelInformation->m_busName, ebusSenderNodeModelInformation->m_eventName, ebusSenderNodeModelInformation->m_busId, ebusSenderNodeModelInformation->m_eventId, ebusSenderNodeModelInformation->m_isOverload, ebusSenderNodeModelInformation->m_propertyStatus);
}
}
@@ -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}");
@@ -33,6 +33,8 @@ namespace ScriptCanvas
Event,
Free,
Member,
Getter,
Setter,
Count,
};
@@ -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()
{
@@ -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;
}
@@ -537,6 +537,20 @@ namespace ScriptCanvas
return azrtti_istypeof<const ScriptCanvas::Nodes::Logic::Break*>(execution->GetId().m_node);
}
bool IsClassPropertyRead(ExecutionTreeConstPtr execution)
{
return execution->GetSymbol() == Symbol::FunctionCall
&& azrtti_istypeof<const ScriptCanvas::Nodes::Core::Method*>(execution->GetId().m_node)
&& azrtti_cast<const ScriptCanvas::Nodes::Core::Method*>(execution->GetId().m_node)->GetPropertyStatus() == PropertyStatus::Getter;
}
bool IsClassPropertyWrite(ExecutionTreeConstPtr execution)
{
return execution->GetSymbol() == Symbol::FunctionCall
&& azrtti_istypeof<const ScriptCanvas::Nodes::Core::Method*>(execution->GetId().m_node)
&& azrtti_cast<const ScriptCanvas::Nodes::Core::Method*>(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<const Slot*>& previousIns, GraphExecutionPathTraversalListener& listener);
ExecutionTraversalResult TraverseExecutionConnectionsRecurse(const EndpointResolved& in, AZStd::unordered_set<const Slot*>& previousIns, GraphExecutionPathTraversalListener& listener);
@@ -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);
@@ -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<AZStd::recursive_mutex> 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;
@@ -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);
@@ -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)
@@ -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();
@@ -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());
@@ -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);
@@ -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<const Nodes::Core::EBusEventHandler*>(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<AZ::Uuid>()(azrtti_typeid<ScriptCanvas::Nodes::Core::Method>()));
AZStd::hash_combine(resultHash, AZStd::hash<AZStd::string_view>()(methodClass));
AZStd::hash_combine(resultHash, AZStd::hash<AZStd::string>()(methodName));
AZStd::hash_combine(resultHash, AZStd::hash<AZ::u8>()(static_cast<AZ::u8>(propertyStatus)));
return resultHash;
}
@@ -253,7 +254,7 @@ namespace ScriptCanvas
if (auto* method = azrtti_cast<ScriptCanvas::Nodes::Core::Method*>(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);
}
}
}
@@ -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);
@@ -21,23 +21,24 @@
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/UserSettings/UserSettingsComponent.h>
#include <AzCore/std/containers/vector.h>
#include <AzFramework/IO/LocalFileIO.h>
#include <AzTest/AzTest.h>
#include <Nodes/BehaviorContextObjectTestNode.h>
#include <Nodes/Nodeables/SharedDataSlotExample.h>
#include <Nodes/Nodeables/ValuePointerReferenceExample.h>
#include <ScriptCanvas/Core/Graph.h>
#include <ScriptCanvas/Core/SlotConfigurationDefaults.h>
#include <ScriptCanvas/ScriptCanvasGem.h>
#include <ScriptCanvas/SystemComponent.h>
#include <AzCore/UserSettings/UserSettingsComponent.h>
#include "EntityRefTests.h"
#include "ScriptCanvasTestApplication.h"
#include "ScriptCanvasTestBus.h"
#include "ScriptCanvasTestNodes.h"
#include "ScriptCanvasTestUtilities.h"
#include <Nodes/Nodeables/SharedDataSlotExample.h>
#include <Nodes/Nodeables/ValuePointerReferenceExample.h>
#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);
@@ -496,7 +496,7 @@ namespace ScriptCanvasTests
ScriptCanvas::Nodes::Core::Method* methodNode(nullptr);
SystemRequestBus::BroadcastResult(methodNode, &SystemRequests::GetNode<ScriptCanvas::Nodes::Core::Method>, methodNodeID);
EXPECT_TRUE(methodNode != nullptr);
methodNode->InitializeBehaviorMethod(emptyNamespaces, className, methodName);
methodNode->InitializeBehaviorMethod(emptyNamespaces, className, methodName, ScriptCanvas::PropertyStatus::None);
return methodNodeID;
}
@@ -30,10 +30,10 @@ namespace ScriptCanvasTestingNodes
{
serializeContext->Class<BehaviorContextObjectTest>()
->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<BehaviorContextObjectTest>("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;
};
@@ -90,6 +90,11 @@ public:
}
};
TEST_F(ScriptCanvasTestFixture, UseRawBehaviorProperties)
{
RunUnitTestGraph("LY_SC_UnitTest_UseRawBehaviorProperties");
}
TEST_F(ScriptCanvasTestFixture, StringSanitization)
{
RunUnitTestGraph("LY_SC_UnitTest_StringSanitization");