Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,174 @@
/*
* 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
#include "AssetRegistryBus.h"
#include <AzCore/EBus/Results.h>
#include <AzCore/Math/Color.h>
namespace ScriptCanvas
{
class AssetDescription
{
public:
AZ_TYPE_INFO(AssetDescription, "{2D2C5BF2-5F94-4A74-AF8B-08AC65A733F7}");
AssetDescription() = default;
AssetDescription( AZ::Data::AssetType assetType,
const char* name,
const char* description,
const char* suggestedSavePath,
const char* fileExtension,
const char* group,
const char* assetNamePattern,
const char* fileFilter,
const char* assetTypeDisplayName,
const char* entityName,
const char* iconPath,
AZ::Color displayColor,
bool isEditableType)
: m_assetType(assetType)
, m_name(name)
, m_description(description)
, m_suggestedSavePath(suggestedSavePath)
, m_fileExtension(fileExtension)
, m_group(group)
, m_assetNamePattern(assetNamePattern)
, m_fileFilter(fileFilter)
, m_assetTypeDisplayName(assetTypeDisplayName)
, m_entityName(entityName)
, m_iconPath(iconPath)
, m_displayColor(displayColor)
, m_isEditableType(isEditableType)
{
}
#define ASSET_DESCRIPTION_GETTER_NT(GetterName) \
static const char* GetterName(AZ::Data::AssetType assetType) { \
AZ::EBusAggregateResults<AssetDescription*> descriptions; \
AssetRegistryRequestBus::EventResult(descriptions, assetType, &AssetRegistryRequests::GetAssetDescription, assetType); \
if (!descriptions.values.empty()) { \
return descriptions.values[0] ? descriptions.values[0]->GetterName##Impl() : ""; } \
return ""; \
}
#define ASSET_DESCRIPTION_GETTER(GetterName) \
template <typename AssetType> \
static const char* GetterName() { \
return GetterName(azrtti_typeid<AssetType>()); \
} \
ASSET_DESCRIPTION_GETTER_NT(GetterName)
ASSET_DESCRIPTION_GETTER(GetName);
ASSET_DESCRIPTION_GETTER(GetDescription);
ASSET_DESCRIPTION_GETTER(GetSuggestedSavePath);
ASSET_DESCRIPTION_GETTER(GetExtension);
ASSET_DESCRIPTION_GETTER(GetGroup);
ASSET_DESCRIPTION_GETTER(GetAssetNamePattern);
ASSET_DESCRIPTION_GETTER(GetFileFilter);
ASSET_DESCRIPTION_GETTER(GetAssetTypeDisplayName);
ASSET_DESCRIPTION_GETTER(GetEntityName);
ASSET_DESCRIPTION_GETTER(GetIconPath);
#define ASSET_DESCRIPTION_GETTER_COLOR_NT(GetterName) \
static AZ::Color GetterName(AZ::Data::AssetType assetType) { \
AZ::EBusAggregateResults<AssetDescription*> descriptions; \
AssetRegistryRequestBus::EventResult(descriptions, assetType, &AssetRegistryRequests::GetAssetDescription, assetType); \
if (!descriptions.values.empty()) { \
return descriptions.values[0] ? descriptions.values[0]->GetterName##Impl() : AZ::Color(0.f,0.f,0.f, 0.f); } \
return AZ::Color(0.f,0.f,0.f, 0.f); \
}
template<typename AssetType>
static AZ::Color GetDisplayColor() {
return GetDisplayColor(azrtti_typeid<AssetType>());
}
ASSET_DESCRIPTION_GETTER_COLOR_NT(GetDisplayColor);
#define ASSET_DESCRIPTION_GETTER_BOOL_NT(GetterName) \
static bool GetterName(AZ::Data::AssetType assetType) { \
AZ::EBusAggregateResults<AssetDescription*> descriptions; \
AssetRegistryRequestBus::EventResult(descriptions, assetType, &AssetRegistryRequests::GetAssetDescription, assetType); \
if (!descriptions.values.empty()) { \
return descriptions.values[0] ? descriptions.values[0]->GetterName##Impl() : false; } \
return false; \
}
template<typename AssetType>
static bool GetIsEditableType() {
return GetIsEditableType(azrtti_typeid<AssetType>());
}
ASSET_DESCRIPTION_GETTER_BOOL_NT(GetIsEditableType);
private:
AZ::Data::AssetType m_assetType;
AZStd::string m_name;
AZStd::string m_description;
AZStd::string m_suggestedSavePath;
AZStd::string m_fileExtension;
AZStd::string m_group;
AZStd::string m_assetNamePattern;
AZStd::string m_fileFilter;
AZStd::string m_assetTypeDisplayName;
AZStd::string m_entityName;
AZStd::string m_iconPath;
AZ::Color m_displayColor;
bool m_isEditableType = false;
public:
AZ::Data::AssetType GetAssetType() const { return m_assetType; }
const char* GetNameImpl() { return m_name.c_str(); }
const char* GetDescriptionImpl() { return m_description.c_str(); }
const char* GetSuggestedSavePathImpl() { return m_suggestedSavePath.c_str(); }
const char* GetExtensionImpl() { return m_fileExtension.c_str(); }
const char* GetGroupImpl() { return m_group.c_str(); }
const char* GetAssetNamePatternImpl() { return m_assetNamePattern.c_str(); }
const char* GetFileFilterImpl() { return m_fileFilter.c_str(); }
const char* GetAssetTypeDisplayNameImpl() { return m_assetTypeDisplayName.c_str(); }
const char* GetEntityNameImpl() { return m_entityName.c_str(); }
const char* GetIconPathImpl() { return m_iconPath.c_str(); }
AZ::Color GetDisplayColorImpl() { return m_displayColor; }
bool GetIsEditableTypeImpl() { return m_isEditableType; }
};
#define ASSET_DESCRIPTION(ClassName, Type, Name, Description, SuggestedSavePath, FileExtension, Group, AssetNamePattern, FileFilter, AssetTypeDisplayName, EntityName, IconPath) \
template <> \
class AssetDescription<Type> \
{ \
public: \
AssetDescription<Type>() \
: m_assetType(azrtti_typeid<Type>()) \
, m_name(Name) \
, m_description(Description) \
, m_suggestedSavePath(SuggestedSavePath) \
, m_fileExtension(FileExtension) \
, m_group(Group) \
, m_assetNamePattern(AssetNamePattern) \
, m_fileFilter(FileFilter) \
, m_assetTypeDisplayName(AssetTypeDisplayName) \
, m_entityName(EntityName) \
, m_iconPath(IconPath) \
{} \
};
}
@@ -0,0 +1,75 @@
/*
* 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 <Asset/AssetRegistry.h>
#include <AzCore/Asset/AssetManager.h>
#include <ScriptCanvas/Asset/RuntimeAsset.h>
#include <ScriptCanvas/Asset/RuntimeAssetHandler.h>
#include <AzCore/std/smart_ptr/make_shared.h>
namespace ScriptCanvas
{
void AssetRegistry::Unregister()
{
for (auto& handler : m_assetHandlers)
{
AZ::Data::AssetManager::Instance().UnregisterHandler(handler.second.get());
}
}
AZ::Data::AssetHandler* AssetRegistry::GetAssetHandler()
{
const AssetRegistryRequestBus::BusIdType assetType = *AssetRegistryRequestBus::GetCurrentBusId();
return GetAssetHandler(assetType);
}
AssetDescription* AssetRegistry::GetAssetDescription(AZ::Data::AssetType assetType)
{
if (m_assetDescription.find(assetType) != m_assetDescription.end())
{
return &m_assetDescription[assetType];
}
return nullptr;
}
AZStd::vector<AZStd::string> AssetRegistry::GetAssetHandlerFileFilters()
{
AZStd::vector<AZStd::string> filters;
for (auto filter : m_assetHandlerFileFilter)
{
filters.push_back(filter.second);
}
return filters;
}
AZ::Data::AssetHandler* AssetRegistry::GetAssetHandler(const AZ::Data::AssetType& assetType)
{
if (m_assetHandlers.find(assetType) != m_assetHandlers.end())
{
return m_assetHandlers[assetType].get();
}
return nullptr;
}
AssetRegistry::AssetRegistry()
{
}
AssetRegistry::~AssetRegistry()
{
AssetRegistryRequestBus::MultiHandler::BusDisconnect();
}
}
@@ -0,0 +1,89 @@
/*
* 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
#include <AzCore/Component/Component.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/Asset/AssetManager.h>
#include <ScriptCanvas/Asset/AssetRegistryBus.h>
#include <ScriptCanvas/Asset/AssetDescription.h>
namespace ScriptCanvas
{
class AssetRegistry
: AssetRegistryRequestBus::MultiHandler
{
public:
AZ_CLASS_ALLOCATOR(AssetRegistry, AZ::SystemAllocator, 0);
AssetRegistry();
~AssetRegistry();
template <typename AssetType, typename HandlerType, typename AssetDescriptionType>
void Register()
{
AZ::Data::AssetType assetType(azrtti_typeid<AssetType>());
if (AZ::Data::AssetManager::Instance().GetHandler(assetType))
{
return; // Asset Type already handled
}
m_assetHandlers[assetType] = AZStd::make_unique<HandlerType>();
AZ::Data::AssetManager::Instance().RegisterHandler(m_assetHandlers[assetType].get(), assetType);
AssetDescriptionType assetDescription;
m_assetDescription[assetType] = assetDescription;
//AZ_TracePrintf("Asset Registry", "AssetRegistry registering: %s (extension: %s)\n", assetType.ToString<AZStd::string>().c_str(), assetDescription.GetExtensionImpl());
// Use AssetCatalog service to register ScriptCanvas asset type and extension
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequests::AddAssetType, assetType);
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequests::EnableCatalogForAsset, assetType);
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequests::AddExtension, assetDescription.GetExtensionImpl());
if (m_assetHandlerFileFilter.find(assetType) == m_assetHandlerFileFilter.end()
&& assetDescription.GetIsEditableTypeImpl())
{
m_assetHandlerFileFilter[assetType] = assetDescription.GetFileFilterImpl();
}
AssetRegistryRequestBus::MultiHandler::BusConnect(assetType);
}
void Unregister();
template <typename AssetType>
AZ::Data::AssetHandler* GetAssetHandler()
{
AZ::Data::AssetType assetType(azrtti_typeid<AssetType>());
return GetAssetHandler(assetType);
}
// AssetRegistryRequestBus
AZ::Data::AssetHandler* GetAssetHandler() override;
AssetDescription* GetAssetDescription(AZ::Data::AssetType assetType) override;
AZStd::vector<AZStd::string> GetAssetHandlerFileFilters() override;
private:
AZ::Data::AssetHandler* GetAssetHandler(const AZ::Data::AssetType& assetType);
AssetRegistry(const AssetRegistry&) = delete;
AZStd::unordered_map<AZ::Data::AssetType, AZStd::unique_ptr<AZ::Data::AssetHandler>> m_assetHandlers;
AZStd::unordered_map<AZ::Data::AssetType, AssetDescription> m_assetDescription;
AZStd::unordered_map<AZ::Data::AssetType, AZStd::string> m_assetHandlerFileFilter;
};
}
@@ -0,0 +1,38 @@
/*
* 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
#include <AzCore/Component/Component.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/Asset/AssetManager.h>
namespace ScriptCanvas
{
class AssetDescription;
class AssetRegistryRequests : public AZ::EBusTraits
{
public:
using BusIdType = AZ::Data::AssetType;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
virtual AZ::Data::AssetHandler* GetAssetHandler() = 0;
virtual AssetDescription* GetAssetDescription(AZ::Data::AssetType assetType) = 0;
virtual AZStd::vector<AZStd::string> GetAssetHandlerFileFilters() = 0;
};
using AssetRegistryRequestBus = AZ::EBus<AssetRegistryRequests>;
}
@@ -0,0 +1,103 @@
/*
* 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 "ExecutionLogAsset.h"
#include <AzCore/IO/FileIO.h>
namespace ScriptCanvas
{
ExecutionLogData::ExecutionLogData(const ExecutionLogData& source)
{
*this = source;
}
ExecutionLogData::ExecutionLogData(ExecutionLogData&& other)
: m_events(AZStd::move(other.m_events))
{
}
ExecutionLogData::~ExecutionLogData()
{
Clear();
}
void ExecutionLogData::Clear()
{
for (auto entry : m_events)
{
delete entry;
}
m_events.resize(0);
}
ExecutionLogData& ExecutionLogData::operator=(const ExecutionLogData& source)
{
Clear();
m_events.reserve(source.m_events.size());
for (auto entry : source.m_events)
{
AZ_Assert(entry, "there should never bee a nullptr entry in an event log");
m_events.push_back(entry->Duplicate());
}
return *this;
}
ExecutionLogData& ExecutionLogData::operator=(ExecutionLogData&& other)
{
if (this != &other)
{
m_events = AZStd::move(other.m_events);
}
return *this;
}
void ExecutionLogData::Reflect(AZ::ReflectContext* reflectContext)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext))
{
serializeContext->Class<ExecutionLogData>()
->Version(0)
->Field("events", &ExecutionLogData::m_events)
;
}
}
void ExecutionLogAsset::Reflect(AZ::ReflectContext* reflectContext)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext))
{
serializeContext->Class<ExecutionLogAsset>()
->Version(0)
->Field("logData", &ExecutionLogAsset::m_logData)
;
}
}
const char* ExecutionLogAsset::GetDefaultDirectoryRoot()
{
return AZ::IO::FileIOBase::GetInstance()->GetAlias("@devroot@");
}
ExecutionLogAsset::ExecutionLogAsset(const AZ::Data::AssetId& assetId, AZ::Data::AssetData::AssetStatus status)
: AZ::Data::AssetData(assetId, status)
{}
void ExecutionLogAsset::SetData(const ExecutionLogData& runtimeData)
{
m_logData = runtimeData;
}
}
@@ -0,0 +1,70 @@
/*
* 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
#include <AzCore/Asset/AssetCommon.h>
#include <ScriptCanvas/Core/ExecutionNotificationsBus.h>
namespace ScriptCanvas
{
struct LoggableEvent;
struct ExecutionLogData
{
AZ_TYPE_INFO(ExecutionLogData, "{8813C6D6-7FC6-4A41-B77B-5B8BFC9C4C01}");
AZ_CLASS_ALLOCATOR(ExecutionLogData, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* reflectContext);
AZStd::vector<LoggableEvent*> m_events;
ExecutionLogData() = default;
ExecutionLogData(const ExecutionLogData& source);
ExecutionLogData(ExecutionLogData&&);
~ExecutionLogData();
void Clear();
ExecutionLogData& operator=(const ExecutionLogData& source);
ExecutionLogData& operator=(ExecutionLogData&&);
};
class ExecutionLogAsset
: public AZ::Data::AssetData
{
public:
AZ_RTTI(ExecutionLogAsset, "{2D49C2E2-2CAF-4F3F-8BED-D613DC16D3F5}", AZ::Data::AssetData);
AZ_CLASS_ALLOCATOR(ExecutionLogAsset, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* reflectContext);
static const char* GetDisplayName() { return "ScriptCanvas Log"; }
static const char* GetGroup() { return "ScriptCanvasLogs"; }
static const char* GetFileExtension() { return "scriptcanvas_log"; }
static const char* GetFileFilter() { return "*.scriptcanvas_log"; }
static const char* GetDefaultDirectoryRoot();
static const char* GetDefaultDirectoryPath() { return "/Gems/ScriptCanvas/Assets/Logs/"; }
ExecutionLogAsset(const AZ::Data::AssetId& assetId = AZ::Data::AssetId(), AZ::Data::AssetData::AssetStatus status = AZ::Data::AssetData::AssetStatus::NotLoaded);
const ExecutionLogData& GetData() const { return m_logData; }
ExecutionLogData& GetData() { return m_logData; }
void SetData(const ExecutionLogData& runtimeData);
protected:
friend class ExecutionLogAssetHandler;
ExecutionLogAsset(const ExecutionLogAsset&) = delete;
ExecutionLogData m_logData;
};
}
@@ -0,0 +1,35 @@
/*
* 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
#include <AzCore/EBus/EBus.h>
#include <ScriptCanvas/Asset/ExecutionLogAsset.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
namespace ScriptCanvas
{
class ExecutionLogAssetBus
: public AZ::EBusTraits
{
public:
virtual void ClearLog() = 0;
virtual void ClearLogExecutionOverride() = 0;
virtual AZ::Data::Asset<ExecutionLogAsset> LoadFromRelativePath(AZStd::string_view path) = 0;
virtual void SaveToRelativePath(AZStd::string_view path) = 0;
virtual void SetLogExecutionOverride(bool value) = 0;
};
using ExecutionLogAssetEBus = AZ::EBus<ExecutionLogAssetBus>;
}
@@ -0,0 +1,153 @@
/*
* 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 <ScriptCanvas/Core/Graph.h>
#include <ScriptCanvas/Asset/RuntimeAsset.h>
#include <ScriptCanvas/Asset/Functions/RuntimeFunctionAssetHandler.h>
#include <ScriptCanvas/Execution/RuntimeComponent.h>
#include <ScriptCanvas/Core/ScriptCanvasBus.h>
#include <AzCore/IO/GenericStreams.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/Serialization/Utils.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Component/Entity.h>
namespace ScriptCanvas
{
//=========================================================================
// RuntimeFunctionAssetHandler
//=========================================================================
RuntimeFunctionAssetHandler::RuntimeFunctionAssetHandler(AZ::SerializeContext* context)
{
SetSerializeContext(context);
AZ::AssetTypeInfoBus::MultiHandler::BusConnect(AZ::AzTypeInfo<ScriptCanvas::RuntimeFunctionAsset>::Uuid());
}
RuntimeFunctionAssetHandler::~RuntimeFunctionAssetHandler()
{
AZ::AssetTypeInfoBus::MultiHandler::BusDisconnect();
}
AZ::Data::AssetType RuntimeFunctionAssetHandler::GetAssetType() const
{
return AZ::AzTypeInfo<RuntimeFunctionAsset>::Uuid();
}
const char* RuntimeFunctionAssetHandler::GetAssetTypeDisplayName() const
{
return "Script Canvas Runtime Function Graph";
}
const char* RuntimeFunctionAssetHandler::GetGroup() const
{
return "Script";
}
const char* RuntimeFunctionAssetHandler::GetBrowserIcon() const
{
return "Editor/Icons/ScriptCanvas/Viewport/ScriptCanvas_Function.png";
}
AZ::Uuid RuntimeFunctionAssetHandler::GetComponentTypeId() const
{
return azrtti_typeid<RuntimeComponent>();
}
void RuntimeFunctionAssetHandler::GetAssetTypeExtensions(AZStd::vector<AZStd::string>& extensions)
{
const AZ::Uuid& assetType = *AZ::AssetTypeInfoBus::GetCurrentBusId();
if (assetType == AZ::AzTypeInfo<ScriptCanvas::RuntimeFunctionAsset>::Uuid())
{
extensions.push_back(ScriptCanvas::RuntimeFunctionAsset::GetFileExtension());
}
}
bool RuntimeFunctionAssetHandler::CanCreateComponent([[maybe_unused]] const AZ::Data::AssetId& assetId) const
{
// This is a runtime component so we shouldn't be making components at edit time for this
return false;
}
AZ::Data::AssetPtr RuntimeFunctionAssetHandler::CreateAsset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type)
{
(void)type;
AZ_Assert(type == AZ::AzTypeInfo<ScriptCanvas::RuntimeFunctionAsset>::Uuid(), "This handler deals only with the Script Canvas Runtime Asset type!");
return aznew ScriptCanvas::RuntimeFunctionAsset(id);
}
AZ::Data::AssetHandler::LoadResult RuntimeFunctionAssetHandler::LoadAssetData(
const AZ::Data::Asset<AZ::Data::AssetData>& asset,
AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
const AZ::Data::AssetFilterCB& assetLoadFilterCB)
{
ScriptCanvas::RuntimeFunctionAsset* runtimeFunctionAsset = asset.GetAs<ScriptCanvas::RuntimeFunctionAsset>();
AZ_Assert(runtimeFunctionAsset, "This should be a Script Canvas runtime asset, as this is the only type we process!");
if (runtimeFunctionAsset && m_serializeContext)
{
stream->Seek(0U, AZ::IO::GenericStream::ST_SEEK_BEGIN);
bool loadSuccess = AZ::Utils::LoadObjectFromStreamInPlace(*stream, runtimeFunctionAsset->m_runtimeData, m_serializeContext, AZ::ObjectStream::FilterDescriptor(assetLoadFilterCB));
return loadSuccess ? AZ::Data::AssetHandler::LoadResult::LoadComplete : AZ::Data::AssetHandler::LoadResult::Error;
}
return AZ::Data::AssetHandler::LoadResult::Error;
}
bool RuntimeFunctionAssetHandler::SaveAssetData(const AZ::Data::Asset<AZ::Data::AssetData>& asset, AZ::IO::GenericStream* stream)
{
ScriptCanvas::RuntimeFunctionAsset* runtimeFunctionAsset = asset.GetAs<ScriptCanvas::RuntimeFunctionAsset>();
AZ_Assert(runtimeFunctionAsset, "This should be a Script Canvas runtime asset, as this is the only type we process!");
if (runtimeFunctionAsset && m_serializeContext)
{
AZ::ObjectStream* binaryObjStream = AZ::ObjectStream::Create(stream, *m_serializeContext, AZ::ObjectStream::ST_XML);
bool graphSaved = binaryObjStream->WriteClass(&runtimeFunctionAsset->m_runtimeData);
binaryObjStream->Finalize();
return graphSaved;
}
return false;
}
void RuntimeFunctionAssetHandler::DestroyAsset(AZ::Data::AssetPtr ptr)
{
delete ptr;
}
void RuntimeFunctionAssetHandler::GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes)
{
assetTypes.push_back(AZ::AzTypeInfo<ScriptCanvas::RuntimeFunctionAsset>::Uuid());
}
AZ::SerializeContext* RuntimeFunctionAssetHandler::GetSerializeContext() const
{
return m_serializeContext;
}
void RuntimeFunctionAssetHandler::SetSerializeContext(AZ::SerializeContext* context)
{
m_serializeContext = context;
if (m_serializeContext == nullptr)
{
// use the default app serialize context
AZ::ComponentApplicationBus::BroadcastResult(m_serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
if (!m_serializeContext)
{
AZ_Error("Script Canvas", false, "RuntimeFunctionAssetHandler: No serialize context provided! We will not be able to process the Script Canvas Runtime Asset type");
}
}
}
} // namespace AZ
@@ -0,0 +1,80 @@
/*
* 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
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Asset/AssetTypeInfoBus.h>
namespace AZ
{
class SerializeContext;
}
namespace ScriptCanvas
{
/**
* Manages Script Canvas graph assets.
*/
class RuntimeFunctionAssetHandler
: public AZ::Data::AssetHandler
, protected AZ::AssetTypeInfoBus::MultiHandler
{
public:
AZ_CLASS_ALLOCATOR(RuntimeFunctionAssetHandler, AZ::SystemAllocator, 0);
AZ_RTTI(RuntimeFunctionAssetHandler, "{560A330A-2905-4A43-952D-70E21F8CE16C}", AZ::Data::AssetHandler);
RuntimeFunctionAssetHandler(AZ::SerializeContext* context = nullptr);
~RuntimeFunctionAssetHandler() override;
// AZ::AssetTypeInfoBus
AZ::Data::AssetType GetAssetType() const override;
const char* GetAssetTypeDisplayName() const override;
const char* GetGroup() const override;
const char* GetBrowserIcon() const override;
AZ::Uuid GetComponentTypeId() const override;
void GetAssetTypeExtensions(AZStd::vector<AZStd::string>& extensions) override;
bool CanCreateComponent(const AZ::Data::AssetId& /*assetId*/) const override;
////
// Called by the asset database to create a new asset. No loading should during this call
AZ::Data::AssetPtr CreateAsset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override;
// Called by the asset database to perform actual asset load.
AZ::Data::AssetHandler::LoadResult LoadAssetData(
const AZ::Data::Asset<AZ::Data::AssetData>& asset,
AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
const AZ::Data::AssetFilterCB& assetLoadFilterCB) override;
// Called by the asset database to perform actual asset save. Returns true if successful otherwise false (default - as we don't require support save).
bool SaveAssetData(const AZ::Data::Asset<AZ::Data::AssetData>& asset, AZ::IO::GenericStream* stream) override;
// Called by the asset database when an asset should be deleted.
void DestroyAsset(AZ::Data::AssetPtr ptr) override;
// Called by asset database on registration.
void GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes) override;
AZ::SerializeContext* GetSerializeContext() const;
void SetSerializeContext(AZ::SerializeContext* context);
protected:
// Workaround for VS2013 - Delete the copy constructor and make it private
// https://connect.microsoft.com/VisualStudio/feedback/details/800328/std-is-copy-constructible-is-broken
RuntimeFunctionAssetHandler(const RuntimeFunctionAssetHandler&) = delete;
AZ::SerializeContext* m_serializeContext;
};
}
@@ -0,0 +1,162 @@
/*
* 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
#include <AzCore/Asset/AssetCommon.h>
#include <ScriptCanvas/Asset/AssetDescription.h>
#include <ScriptCanvas/Asset/ScriptCanvasAssetBase.h>
#include <AzCore/std/containers/vector.h>
namespace AZ
{
class Entity;
}
namespace ScriptCanvas
{
class ScriptCanvasFunctionAsset;
}
namespace ScriptCanvas
{
class Graph;
class ScriptCanvasFunctionDescription : public AssetDescription
{
public:
AZ_TYPE_INFO(ScriptCanvasFunctionDescription, "{B53569F6-8408-40FC-9A72-ED873BEF162E}");
ScriptCanvasFunctionDescription()
: ScriptCanvas::AssetDescription(
azrtti_typeid<ScriptCanvasFunctionAsset>(),
"Script Canvas Function",
"Script Canvas Function Graph Asset",
"@devassets@/scriptcanvas/functions",
".scriptcanvas_fn",
"Script Canvas Function",
"Untitled-Function-%i",
"Script Canvas Function Files (*.scriptcanvas_fn)",
"Script Canvas Function",
"Script Canvas Function",
"Editor/Icons/ScriptCanvas/Viewport/ScriptCanvas_Function.png",
AZ::Color(0.192f, 0.149f, 0.392f, 1.0f),
true
)
{}
};
}
namespace ScriptCanvas
{
// TODO-LS: move these to their own file
class ScriptCanvasDataRequests : public AZ::ComponentBus
{
public:
virtual void SetPrettyName(const char* name) = 0;
virtual AZStd::string GetPrettyName() = 0;
};
using ScriptCanvasDataRequestBus = AZ::EBus< ScriptCanvasDataRequests>;
class ScriptCanvasFunctionDataComponent
: public AZ::Component
, ScriptCanvasDataRequestBus::MultiHandler
{
public:
AZ_COMPONENT(ScriptCanvasFunctionDataComponent, "{440BB6DC-4E70-4304-A926-252925F77433}");
void Activate() override
{
AZ::EntityId entityId = GetEntityId();
ScriptCanvasDataRequestBus::MultiHandler::BusConnect(entityId);
}
void Deactivate() override
{
ScriptCanvasDataRequestBus::MultiHandler::BusDisconnect();
AZ::EntityId entityId = GetEntityId();
}
void SetPrettyName(const char* name) override
{
m_assetPrettyName = name;
}
AZStd::string GetPrettyName() override
{
return m_assetPrettyName;
}
static void Reflect(AZ::ReflectContext* reflectContext)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext))
{
serializeContext->Class<ScriptCanvasFunctionDataComponent, AZ::Component>()
->Version(1)
->Field("m_assetPrettyName", &ScriptCanvasFunctionDataComponent::m_assetPrettyName)
->Field("m_executionNodeOrder", &ScriptCanvasFunctionDataComponent::m_executionNodeOrder)
->Field("m_variableOrder", &ScriptCanvasFunctionDataComponent::m_variableOrder)
->Field("m_version", &ScriptCanvasFunctionDataComponent::m_version)
;
}
}
size_t m_version = 0;
AZStd::string m_assetPrettyName;
AZStd::vector<ScriptCanvas::ID> m_executionNodeOrder; // These represent execution inputs or outputs
AZStd::vector<VariableId> m_variableOrder;
};
class ScriptCanvasFunctionAsset
: public ScriptCanvasAssetBase
{
public:
AZ_RTTI(ScriptCanvasFunctionAsset, "{ED078D3C-938D-41F8-A5F6-CC04311ECF4F}", ScriptCanvasAssetBase);
AZ_CLASS_ALLOCATOR(ScriptCanvasFunctionAsset, AZ::SystemAllocator, 0);
ScriptCanvasFunctionAsset(const AZ::Data::AssetId& assetId = AZ::Data::AssetId(AZ::Uuid::CreateRandom()), AZ::Data::AssetData::AssetStatus status = AZ::Data::AssetData::AssetStatus::NotLoaded)
: ScriptCanvasAssetBase(assetId, status)
{
m_data = aznew ScriptCanvasData();
}
~ScriptCanvasFunctionAsset() override
{}
ScriptCanvas::AssetDescription GetAssetDescription() const override
{
return ScriptCanvas::ScriptCanvasFunctionDescription();
}
using Description = ScriptCanvasFunctionDescription;
ScriptCanvasFunctionDataComponent* m_cachedComponent = nullptr;
ScriptCanvasFunctionDataComponent* GetFunctionData()
{
if (m_cachedComponent == nullptr)
{
m_cachedComponent = GetScriptCanvasEntity()->FindComponent<ScriptCanvasFunctionDataComponent>();
}
return m_cachedComponent;
}
};
} // namespace ScriptCanvasEditor
@@ -0,0 +1,94 @@
/*
* 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 "RuntimeAsset.h"
#include <AzCore/Component/Entity.h>
namespace ScriptCanvas
{
void RuntimeData::Reflect(AZ::ReflectContext* reflectContext)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext))
{
serializeContext->Class<RuntimeData>()
->Version(0)
->Field("m_graphData", &RuntimeData::m_graphData)
->Field("m_variableData", &RuntimeData::m_variableData)
;
}
}
RuntimeData::RuntimeData(RuntimeData&& other)
: m_graphData(AZStd::move(other.m_graphData))
, m_variableData(AZStd::move(other.m_variableData))
{
}
RuntimeData& RuntimeData::operator=(RuntimeData&& other)
{
if (this != &other)
{
m_graphData = AZStd::move(other.m_graphData);
m_variableData = AZStd::move(other.m_variableData);
}
return *this;
}
////////////////////////
// FunctionRuntimeData
////////////////////////
void FunctionRuntimeData::Reflect(AZ::ReflectContext* reflectContext)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext))
{
serializeContext->Class<FunctionRuntimeData, RuntimeData>()
->Version(3)
->Field("m_name", &FunctionRuntimeData::m_name)
->Field("m_version", &FunctionRuntimeData::m_version)
->Field("m_executionNodeOrder", &FunctionRuntimeData::m_executionNodeOrder)
->Field("m_variableOrder", &FunctionRuntimeData::m_variableOrder)
;
}
}
FunctionRuntimeData::FunctionRuntimeData(FunctionRuntimeData&& other)
: RuntimeData(other)
, m_name(AZStd::move(other.m_name))
, m_version(AZStd::move(other.m_version))
, m_executionNodeOrder(AZStd::move(other.m_executionNodeOrder))
, m_variableOrder(AZStd::move(other.m_variableOrder))
{
}
FunctionRuntimeData& FunctionRuntimeData::operator=(FunctionRuntimeData&& other)
{
if (this != &other)
{
m_name = AZStd::move(other.m_name);
m_version = AZStd::move(other.m_version);
m_graphData = AZStd::move(other.m_graphData);
m_variableData = AZStd::move(other.m_variableData);
m_executionNodeOrder = AZStd::move(other.m_executionNodeOrder);
m_variableOrder = AZStd::move(other.m_variableOrder);
}
return *this;
}
///////
}
@@ -0,0 +1,204 @@
/*
* 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
#include <AzCore/Asset/AssetCommon.h>
#include <ScriptCanvas/Core/GraphData.h>
#include <ScriptCanvas/Variable/VariableData.h>
#include <ScriptCanvas/Asset/AssetDescription.h>
namespace ScriptCanvas
{
class RuntimeAsset;
class RuntimeAssetDescription : public AssetDescription
{
public:
AZ_TYPE_INFO(RuntimeAssetDescription, "{7F49CB81-0655-4AF6-A1B5-95417A6FD568}");
RuntimeAssetDescription()
: AssetDescription(
azrtti_typeid<RuntimeAsset>(),
"Script Canvas Runtime",
"Script Canvas Runtime Graph",
"@devassets@/scriptcanvas",
".scriptcanvas_compiled",
"Script Canvas Runtime",
"Untitled-%i",
"Script Canvas Files (*.scriptcanvas_compiled)",
"Script Canvas Runtime",
"Script Canvas Runtime",
"Editor/Icons/ScriptCanvas/Viewport/ScriptCanvas.png",
AZ::Color(1.0f,0.0f,0.0f,1.0f),
false
)
{}
};
struct RuntimeData
{
AZ_TYPE_INFO(RuntimeData, "{A935EBBC-D167-4C59-927C-5D98C6337B9C}");
AZ_CLASS_ALLOCATOR(RuntimeData, AZ::SystemAllocator, 0);
RuntimeData() = default;
~RuntimeData() = default;
RuntimeData(const RuntimeData&) = default;
RuntimeData& operator=(const RuntimeData&) = default;
RuntimeData(RuntimeData&&);
RuntimeData& operator=(RuntimeData&&);
static void Reflect(AZ::ReflectContext* reflectContext);
GraphData m_graphData;
VariableData m_variableData;
};
class RuntimeAssetBase
: public AZ::Data::AssetData
{
public:
AZ_RTTI(RuntimeAssetBase, "{19BAD220-E505-4443-AA95-743106748F37}", AZ::Data::AssetData);
AZ_CLASS_ALLOCATOR(RuntimeAssetBase, AZ::SystemAllocator, 0);
RuntimeAssetBase(const AZ::Data::AssetId& assetId = AZ::Data::AssetId(), AZ::Data::AssetData::AssetStatus status = AZ::Data::AssetData::AssetStatus::NotLoaded)
: AZ::Data::AssetData(assetId, status)
{
}
};
template <typename DataType>
class RuntimeAssetTyped
: public RuntimeAssetBase
{
public:
AZ_RTTI(RuntimeAssetBase, "{C925213E-A1FA-4487-831F-9551A984700E}", RuntimeAssetBase);
AZ_CLASS_ALLOCATOR(RuntimeAssetBase, AZ::SystemAllocator, 0);
RuntimeAssetTyped(const AZ::Data::AssetId& assetId = AZ::Data::AssetId(), AZ::Data::AssetData::AssetStatus status = AZ::Data::AssetData::AssetStatus::NotLoaded)
: RuntimeAssetBase(assetId, status)
{
}
~RuntimeAssetTyped() override { m_runtimeData.m_graphData.Clear(true); }
static const char* GetFileExtension() { return "scriptcanvas_compiled"; }
static const char* GetFileFilter() { return "*.scriptcanvas_compiled"; }
const DataType& GetData() const { return m_runtimeData; }
DataType& GetData() { return m_runtimeData; }
void SetData(const DataType& runtimeData)
{
m_runtimeData = runtimeData;
// When setting data instead of serializing, immediately mark the asset as ready.
m_status = AZ::Data::AssetData::AssetStatus::Ready;
}
DataType m_runtimeData;
protected:
friend class RuntimeAssetHandler;
RuntimeAssetTyped(const RuntimeAssetTyped&) = delete;
};
class RuntimeAsset : public RuntimeAssetTyped<RuntimeData>
{
public:
AZ_RTTI(RuntimeAsset, "{3E2AC8CD-713F-453E-967F-29517F331784}", RuntimeAssetTyped<RuntimeData>);
RuntimeAsset(const AZ::Data::AssetId& assetId = AZ::Data::AssetId(), AZ::Data::AssetData::AssetStatus status = AZ::Data::AssetData::AssetStatus::NotLoaded)
: RuntimeAssetTyped<RuntimeData>(assetId, status)
{
}
};
class RuntimeFunctionAsset;
class RuntimeFunctionAssetDescription : public AssetDescription
{
public:
AZ_TYPE_INFO(RuntimeFunctionAssetDescription, "{7F7BE1A5-9447-41C2-9190-18580075094C}");
RuntimeFunctionAssetDescription()
: AssetDescription(
azrtti_typeid<RuntimeFunctionAsset>(),
"Script Canvas Runtime Function",
"Script Canvas Runtime Function Graph",
"@devassets@/scriptcanvas",
".scriptcanvas_fn_compiled",
"Script Canvas Runtime Function",
"Untitled-Function-%i",
"Script Canvas Compiled Function Files (*.scriptcanvas_fn_compiled)",
"Script Canvas Runtime Function",
"Script Canvas Runtime Function",
"Editor/Icons/ScriptCanvas/Viewport/ScriptCanvas_Function.png",
AZ::Color(1.0f,0.0f,0.0f,1.0f),
false
)
{}
};
struct FunctionRuntimeData : public RuntimeData
{
AZ_TYPE_INFO(FunctionRuntimeData, "{1734C569-7D40-4491-9EEE-A225E333C9BA}");
AZ_CLASS_ALLOCATOR(FunctionRuntimeData, AZ::SystemAllocator, 0);
FunctionRuntimeData() = default;
~FunctionRuntimeData() = default;
FunctionRuntimeData(const FunctionRuntimeData&) = default;
FunctionRuntimeData& operator=(const FunctionRuntimeData&) = default;
FunctionRuntimeData(FunctionRuntimeData&&);
FunctionRuntimeData& operator=(FunctionRuntimeData&&);
static void Reflect(AZ::ReflectContext* reflectContext);
size_t m_version;
AZStd::string m_name;
AZStd::vector< AZ::EntityId > m_executionNodeOrder;
AZStd::vector< VariableId > m_variableOrder;
};
class RuntimeFunctionAsset
: public RuntimeAssetTyped<FunctionRuntimeData>
{
public:
AZ_RTTI(RuntimeFunctionAsset, "{E22967AC-7673-4778-9125-AF49D82CAF9F}", RuntimeAssetTyped<FunctionRuntimeData>);
AZ_CLASS_ALLOCATOR(RuntimeFunctionAsset, AZ::SystemAllocator, 0);
RuntimeFunctionAsset(const AZ::Data::AssetId& assetId = AZ::Data::AssetId(), AZ::Data::AssetData::AssetStatus status = AZ::Data::AssetData::AssetStatus::NotLoaded)
: RuntimeAssetTyped<FunctionRuntimeData>(assetId, status)
{}
~RuntimeFunctionAsset() override
{
m_runtimeData.m_graphData.Clear(true);
}
void SetData(const FunctionRuntimeData& runtimeData)
{
m_runtimeData = runtimeData;
}
static const char* GetFileExtension() { return "scriptcanvas_fn_compiled"; }
static const char* GetFileFilter() { return "*.scriptcanvas_fn_compiled"; }
friend class RuntimeFunctionAssetHandler;
};
}
@@ -0,0 +1,153 @@
/*
* 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 <ScriptCanvas/Core/Graph.h>
#include <ScriptCanvas/Asset/RuntimeAsset.h>
#include <ScriptCanvas/Asset/RuntimeAssetHandler.h>
#include <ScriptCanvas/Execution/RuntimeComponent.h>
#include <ScriptCanvas/Core/ScriptCanvasBus.h>
#include <AzCore/IO/GenericStreams.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/Serialization/Utils.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Component/Entity.h>
namespace ScriptCanvas
{
//=========================================================================
// RuntimeAssetHandler
//=========================================================================
RuntimeAssetHandler::RuntimeAssetHandler(AZ::SerializeContext* context)
{
SetSerializeContext(context);
AZ::AssetTypeInfoBus::MultiHandler::BusConnect(AZ::AzTypeInfo<RuntimeAsset>::Uuid());
}
RuntimeAssetHandler::~RuntimeAssetHandler()
{
AZ::AssetTypeInfoBus::MultiHandler::BusDisconnect();
}
AZ::Data::AssetType RuntimeAssetHandler::GetAssetType() const
{
return AZ::AzTypeInfo<RuntimeAsset>::Uuid();
}
const char* RuntimeAssetHandler::GetAssetTypeDisplayName() const
{
return "Script Canvas Runtime Graph";
}
const char* RuntimeAssetHandler::GetGroup() const
{
return "Script";
}
const char* RuntimeAssetHandler::GetBrowserIcon() const
{
return "Editor/Icons/ScriptCanvas/Viewport/ScriptCanvas.png";
}
AZ::Uuid RuntimeAssetHandler::GetComponentTypeId() const
{
return azrtti_typeid<RuntimeComponent>();
}
void RuntimeAssetHandler::GetAssetTypeExtensions(AZStd::vector<AZStd::string>& extensions)
{
const AZ::Uuid& assetType = *AZ::AssetTypeInfoBus::GetCurrentBusId();
if (assetType == AZ::AzTypeInfo<RuntimeAsset>::Uuid())
{
extensions.push_back(RuntimeAsset::GetFileExtension());
}
}
bool RuntimeAssetHandler::CanCreateComponent([[maybe_unused]] const AZ::Data::AssetId& assetId) const
{
// This is a runtime component so we shouldn't be making components at edit time for this
return false;
}
AZ::Data::AssetPtr RuntimeAssetHandler::CreateAsset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type)
{
(void)type;
AZ_Assert(type == AZ::AzTypeInfo<RuntimeAsset>::Uuid(), "This handler deals only with the Script Canvas Runtime Asset type!");
return aznew RuntimeAsset(id);
}
AZ::Data::AssetHandler::LoadResult RuntimeAssetHandler::LoadAssetData(
const AZ::Data::Asset<AZ::Data::AssetData>& asset,
AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
const AZ::Data::AssetFilterCB& assetLoadFilterCB)
{
RuntimeAsset* runtimeAsset = asset.GetAs<RuntimeAsset>();
AZ_Assert(runtimeAsset, "This should be a Script Canvas runtime asset, as this is the only type we process!");
if (runtimeAsset && m_serializeContext)
{
stream->Seek(0U, AZ::IO::GenericStream::ST_SEEK_BEGIN);
bool loadSuccess = AZ::Utils::LoadObjectFromStreamInPlace(*stream, runtimeAsset->m_runtimeData, m_serializeContext, AZ::ObjectStream::FilterDescriptor(assetLoadFilterCB));
return loadSuccess ? AZ::Data::AssetHandler::LoadResult::LoadComplete : AZ::Data::AssetHandler::LoadResult::Error;
}
return AZ::Data::AssetHandler::LoadResult::Error;
}
bool RuntimeAssetHandler::SaveAssetData(const AZ::Data::Asset<AZ::Data::AssetData>& asset, AZ::IO::GenericStream* stream)
{
RuntimeAsset* runtimeAsset = asset.GetAs<RuntimeAsset>();
AZ_Assert(runtimeAsset, "This should be a Script Canvas runtime asset, as this is the only type we process!");
if (runtimeAsset && m_serializeContext)
{
AZ::ObjectStream* binaryObjStream = AZ::ObjectStream::Create(stream, *m_serializeContext, AZ::ObjectStream::ST_XML);
bool graphSaved = binaryObjStream->WriteClass(&runtimeAsset->m_runtimeData);
binaryObjStream->Finalize();
return graphSaved;
}
return false;
}
void RuntimeAssetHandler::DestroyAsset(AZ::Data::AssetPtr ptr)
{
delete ptr;
}
void RuntimeAssetHandler::GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes)
{
assetTypes.push_back(AZ::AzTypeInfo<RuntimeAsset>::Uuid());
}
AZ::SerializeContext* RuntimeAssetHandler::GetSerializeContext() const
{
return m_serializeContext;
}
void RuntimeAssetHandler::SetSerializeContext(AZ::SerializeContext* context)
{
m_serializeContext = context;
if (m_serializeContext == nullptr)
{
// use the default app serialize context
AZ::ComponentApplicationBus::BroadcastResult(m_serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
if (!m_serializeContext)
{
AZ_Error("Script Canvas", false, "RuntimeAssetHandler: No serialize context provided! We will not be able to process the Script Canvas Runtime Asset type");
}
}
}
} // namespace AZ
@@ -0,0 +1,77 @@
/*
* 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
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Asset/AssetTypeInfoBus.h>
namespace AZ
{
class SerializeContext;
}
namespace ScriptCanvas
{
/**
* Manages Script Canvas graph assets.
*/
class RuntimeAssetHandler
: public AZ::Data::AssetHandler
, protected AZ::AssetTypeInfoBus::MultiHandler
{
public:
AZ_CLASS_ALLOCATOR(RuntimeAssetHandler, AZ::SystemAllocator, 0);
AZ_RTTI(RuntimeAssetHandler, "{560A330A-2905-4A43-952D-70E21F8CE16C}", AZ::Data::AssetHandler);
RuntimeAssetHandler(AZ::SerializeContext* context = nullptr);
~RuntimeAssetHandler() override;
// AZ::AssetTypeInfoBus
AZ::Data::AssetType GetAssetType() const override;
const char* GetAssetTypeDisplayName() const override;
const char* GetGroup() const override;
const char* GetBrowserIcon() const override;
AZ::Uuid GetComponentTypeId() const override;
void GetAssetTypeExtensions(AZStd::vector<AZStd::string>& extensions) override;
bool CanCreateComponent(const AZ::Data::AssetId& /*assetId*/) const override;
////
// Called by the asset database to create a new asset. No loading should during this call
AZ::Data::AssetPtr CreateAsset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override;
// Called by the asset database to perform actual asset load.
AZ::Data::AssetHandler::LoadResult LoadAssetData(
const AZ::Data::Asset<AZ::Data::AssetData>& asset,
AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
const AZ::Data::AssetFilterCB& assetLoadFilterCB) override;
// Called by the asset database to perform actual asset save. Returns true if successful otherwise false (default - as we don't require support save).
bool SaveAssetData(const AZ::Data::Asset<AZ::Data::AssetData>& asset, AZ::IO::GenericStream* stream) override;
// Called by the asset database when an asset should be deleted.
void DestroyAsset(AZ::Data::AssetPtr ptr) override;
// Called by asset database on registration.
void GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes) override;
AZ::SerializeContext* GetSerializeContext() const;
void SetSerializeContext(AZ::SerializeContext* context);
protected:
AZ::SerializeContext* m_serializeContext;
};
}
@@ -0,0 +1,94 @@
/*
* 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
#include <AzCore/Asset/AssetCommon.h>
#include <Editor/Include/ScriptCanvas/Assets/ScriptCanvasAssetBus.h>
#include <Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.h>
#include <ScriptCanvas/Asset/AssetDescription.h>
namespace ScriptCanvas
{
class ScriptCanvasAssetBase
: public AZ::Data::AssetData
, ScriptCanvas::ScriptCanvasAssetBusRequestBus::Handler
{
public:
AZ_RTTI(ScriptCanvasAssetBase, "{D07DBDE4-A169-4650-871B-FC75AFEEB03E}", AZ::Data::AssetData);
AZ_CLASS_ALLOCATOR(ScriptCanvasAssetBase, AZ::SystemAllocator, 0);
ScriptCanvasAssetBase(const AZ::Data::AssetId& assetId = AZ::Data::AssetId(AZ::Uuid::CreateRandom()),
AZ::Data::AssetData::AssetStatus status = AZ::Data::AssetData::AssetStatus::NotLoaded)
: AZ::Data::AssetData(assetId, status)
{
ScriptCanvas::ScriptCanvasAssetBusRequestBus::Handler::BusConnect(GetId());
}
virtual ~ScriptCanvasAssetBase()
{
delete m_data;
ScriptCanvas::ScriptCanvasAssetBusRequestBus::Handler::BusDisconnect();
}
template <typename DataType>
DataType* GetScriptCanvasDataAs()
{
return azrtti_cast<DataType*>(m_data);
}
template <typename DataType>
const DataType* GetScriptCanvasDataAs() const
{
return azrtti_cast<DataType*>(m_data);
}
virtual ScriptCanvasData& GetScriptCanvasData()
{
return *m_data;
}
virtual const ScriptCanvasData& GetScriptCanvasData() const
{
return *m_data;
}
AZ::Entity* GetScriptCanvasEntity() const
{
return m_data->m_scriptCanvasEntity.get();
}
virtual void SetScriptCanvasEntity(AZ::Entity* scriptCanvasEntity)
{
if (m_data->m_scriptCanvasEntity.get() != scriptCanvasEntity)
{
m_data->m_scriptCanvasEntity.reset(scriptCanvasEntity);
}
}
virtual ScriptCanvas::AssetDescription GetAssetDescription() const = 0;
protected:
ScriptCanvasData* m_data;
void SetAsNewAsset() override
{
m_status = AZ::Data::AssetData::AssetStatus::Ready;
}
};
} // namespace ScriptCanvas
@@ -0,0 +1,18 @@
/*
* 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
namespace ScriptCanvas
{
}
@@ -0,0 +1,122 @@
{#
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
#include <ScriptCanvas/Core/Datum.h>
#include <ScriptCanvas/Core/Node.h>
{% for xml in dataFiles %}
{% for Class in xml.iter('Class') %}
{% for Include in Class.iter('Include') %}
#include <{{ Include.attrib['File'] }}>
{% endfor %}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
////
//// {{ Class.attrib['Name'] }}
////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// The following will be injected directly into the source header file for which AzCodeGenerator is being run.
// You must #include the generated header into the source header
#define AZ_GENERATED_{{ Class.attrib['Name'] }} \
public: \
AZ_COMPONENT({{ Class.attrib['Name'] }}, "{{ Class.attrib['Uuid'] }}"{% if Class.attrib['Base'] is defined %}, {{ Class.attrib['Base'] }}{% endif %}); \
static void Reflect(AZ::ReflectContext* reflection); \
void ConfigureSlots() override; \
bool RequiresDynamicSlotOrdering() const override; \
bool IsDeprecated() const override; \
using Node::FindDatum; \
{% if Class.attrib['GraphEntryPoint'] is defined %} bool IsEntryPoint() const override { return true; } \
{% endif %}
public: \
friend struct ::{{ Class.attrib['Name'] | replace(' ','') }}Property;
// Helpers for easily accessing properties and slots
struct {{ Class.attrib['Name'] | replace(' ','') }}Property
{
{% for Property in Class.iter('Out') %}
{% if Property.attrib['Description'] is defined %} // {{ Property.attrib['Description'] }}{% endif %}
static ScriptCanvas::SlotId Get{{ Property.attrib['Name'] | replace(' ','') }}SlotId(ScriptCanvas::Node* owner)
{
return owner->GetSlotId("{{ Property.attrib['Name'] | replace(' ','') }}");
}
static ScriptCanvas::Slot* Get{{ Property.attrib['Name'] | replace(' ','') }}Slot(ScriptCanvas::Node* owner)
{
return owner->GetSlot(Get{{ Property.attrib['Name'] | replace(' ','') }}SlotId(owner));
}
{% endfor %}
{% for Property in Class.iter('OutLatent') %}
{% if Property.attrib['Description'] is defined %} // {{ Property.attrib['Description'] }}{% endif %}
static ScriptCanvas::SlotId Get{{ Property.attrib['Name'] | replace(' ','') }}SlotId(ScriptCanvas::Node* owner)
{
return owner->GetSlotId("{{ Property.attrib['Name'] | replace(' ','') }}");
}
static ScriptCanvas::Slot* Get{{ Property.attrib['Name'] | replace(' ','') }}Slot(ScriptCanvas::Node* owner)
{
return owner->GetSlot(Get{{ Property.attrib['Name'] | replace(' ','') }}SlotId(owner));
}
{% endfor %}
{% for Property in Class.iter('In') %}
{% if Property.attrib['Description'] is defined %} // {{ Property.attrib['Description'] }}{% endif %}
static ScriptCanvas::SlotId Get{{ Property.attrib['Name'] | replace(' ','') }}SlotId(ScriptCanvas::Node* owner)
{
return owner->GetSlotId("{{ Property.attrib['Name'] | replace(' ','') }}");
}
static ScriptCanvas::Slot* Get{{ Property.attrib['Name'] | replace(' ','') }}Slot(ScriptCanvas::Node* owner)
{
return owner->GetSlot(Get{{ Property.attrib['Name'] | replace(' ','') }}SlotId(owner));
}
{% endfor %}
{% for Property in Class.iter('Property') %}
{% if Property.attrib['Description'] is defined %} // {{ Property.attrib['Description'] }}{% endif %}
static ScriptCanvas::SlotId Get{{ Property.attrib['Name'] | replace(' ','') }}SlotId(ScriptCanvas::Node* owner)
{
return owner->GetSlotId("{{ Property.attrib['Name'] }}");
}
static ScriptCanvas::Slot* Get{{ Property.attrib['Name'] | replace(' ','') }}Slot(ScriptCanvas::Node* owner)
{
return owner->GetSlot(Get{{ Property.attrib['Name'] | replace(' ','') }}SlotId(owner));
}
static {{ Property.attrib['Type'] }} Get{{ Property.attrib['Name'] | replace(' ','') }}(ScriptCanvas::Node* owner);
{% endfor %}
{% for Property in Class.iter('DynamicDataSlot') %}
{% if Property.attrib['Description'] is defined %} // {{ Property.attrib['Description'] }}{% endif %}
static ScriptCanvas::SlotId Get{{ Property.attrib['Name'] }}SlotId(ScriptCanvas::Node* owner)
{
return owner->GetSlotId("{{ Property.attrib['Name'] }}");
}
static ScriptCanvas::Slot* Get{{ Property.attrib['Name'] }}Slot(ScriptCanvas::Node* owner)
{
return owner->GetSlot(Get{{ Property.attrib['Name'] }}SlotId(owner));
}
{% endfor %}
};
{% endfor %}
{% endfor %}
@@ -0,0 +1,241 @@
{#
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.
#}
{% macro add_attribute(attribute, tags) %}
{% set value = tags[attribute] %}
{% if value is defined %}
->Attribute(AZ::Edit::Attributes::{{ attribute }}, {{ value }})
{% endif %}
{% endmacro %}
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/RTTI/TypeInfo.h>
#include <ScriptCanvas/Core/Slot.h>
#include <ScriptCanvas/Core/Datum.h>
#include <ScriptCanvas/Core/Attributes.h>
#include <ScriptCanvas/Core/Contracts.h>
#include <ScriptCanvas/Core/DatumBus.h>
{% for xml in dataFiles %}
#include "{{ xml.attrib['Include'] }}"
{% for Class in xml.iter('Class') %}
void {{ Class.attrib['QualifiedName'] }}::ConfigureSlots()
{
{% if Class.attrib['Base'] is defined %}
{{ Class.attrib['Base'] }}::ConfigureSlots();
{% endif %}
{% for Property in Class.iter('Property') %}
{% if Property.attrib['IsInput'] | booleanTrue %}
// {{ Property.attrib['Name'] }}
{
{% if Property.attrib['Overloaded'] is defined %}
ScriptCanvas::DynamicDataSlotConfiguration slotConfiguration;
slotConfiguration.m_dynamicDataType = ScriptCanvas::DynamicDataType::Any;
{% else %}
ScriptCanvas::DataSlotConfiguration slotConfiguration;
slotConfiguration.SetAZType<{{ Property.attrib['Type'] }}>();
{% if Property.attrib['DefaultValue'] is defined %}
slotConfiguration.SetDefaultValue({{ Property.attrib['Type'] }}({{ Property.attrib['DefaultValue'] }}));
{% endif %}
{% endif %}
slotConfiguration.m_name = "{{ Property.attrib['Name'] }}";
slotConfiguration.m_toolTip = "{{ Property.attrib['Description'] }}";
{% if Property.attrib['DisplayGroup'] is defined %}
slotConfiguration.m_displayGroup = "{{ Property.attrib['DisplayGroup'] }}";
{% endif %}
slotConfiguration.SetConnectionType(ScriptCanvas::ConnectionType::Input);
AddSlot(slotConfiguration);
}
{% endif %}
{% if Property.attrib['IsOutput'] | booleanTrue %}
// {{ Property.attrib['Name'] }}
{
ScriptCanvas::DataSlotConfiguration slotConfiguration;
slotConfiguration.SetAZType<{{ Property.attrib['Type'] }}>();
slotConfiguration.m_name = "{{ Property.attrib['Name'] }}";
slotConfiguration.m_toolTip = "{{ Property.attrib['Description'] }}";
slotConfiguration.SetConnectionType(ScriptCanvas::ConnectionType::Output);
{% if Property.attrib['DisplayGroup'] is defined %}
slotConfiguration.m_displayGroup = "{{ Property.attrib['DisplayGroup'] }}";
{% endif %}
AddSlot(slotConfiguration);
}
{% endif %}
{% endfor %}
{% for Property in Class.iter('In') %}
// {{ Property.attrib['Name'] }}
{
ScriptCanvas::ExecutionSlotConfiguration slotConfiguration;
slotConfiguration.m_name = "{{ Property.attrib['Name'] }}";
slotConfiguration.m_toolTip = "{{ Property.attrib['Description'] }}";
{% if Property.attrib['DisplayGroup'] is defined %}
slotConfiguration.m_displayGroup = "{{ Property.attrib['DisplayGroup'] }}";
{% endif %}
{% if Property.attrib['Contract'] is defined %}
slotConfiguration.m_contractDescs = AZStd::vector<ScriptCanvas::ContractDescriptor>{ { []() { return aznew {{ Property.attrib['Contract'] }}; } } };
{% endif %}
slotConfiguration.SetConnectionType(ScriptCanvas::ConnectionType::Input);
AddSlot(slotConfiguration);
}
{% endfor %}
{% for Property in Class.iter('Out') %}
// {{ Property.attrib['Name'] }}
{
ScriptCanvas::ExecutionSlotConfiguration slotConfiguration;
slotConfiguration.m_name = "{{ Property.attrib['Name'] }}";
slotConfiguration.m_toolTip = "{{ Property.attrib['Description'] }}";
{% if Property.attrib['DisplayGroup'] is defined %}
slotConfiguration.m_displayGroup = "{{ Property.attrib['DisplayGroup'] }}";
{% endif %}
slotConfiguration.SetConnectionType(ScriptCanvas::ConnectionType::Output);
AddSlot(slotConfiguration);
}
{% endfor %}
{% for Property in Class.iter('OutLatent') %}
// {{ Property.attrib['Name'] }}
{
ScriptCanvas::ExecutionSlotConfiguration slotConfiguration;
slotConfiguration.m_name = "{{ Property.attrib['Name'] }}";
slotConfiguration.m_toolTip = "{{ Property.attrib['Description'] }}";
{% if Property.attrib['DisplayGroup'] is defined %}
slotConfiguration.m_displayGroup = "{{ Property.attrib['DisplayGroup'] }}";
{% endif %}
slotConfiguration.SetConnectionType(ScriptCanvas::ConnectionType::Output);
slotConfiguration.m_isLatent = true;
AddSlot(slotConfiguration);
}
{% endfor %}
{% for Property in Class.iter('DynamicDataSlot') %}
// {{ Property.attrib['Name'] }}
{
ScriptCanvas::DynamicDataSlotConfiguration slotConfiguration;
slotConfiguration.m_name = "{{ Property.attrib['Name'] }}";
slotConfiguration.m_toolTip = "{{ Property.attrib['Description'] }}";
{% if Property.attrib['DisplayGroup'] is defined %}
slotConfiguration.m_displayGroup = "{{ Property.attrib['DisplayGroup'] }}";
{% endif %}
slotConfiguration.SetConnectionType({{ Property.attrib['ConnectionType'] }});
slotConfiguration.m_dynamicDataType = {{ Property.attrib['DynamicType'] }};
{% if Property.attrib['DynamicGroup'] is defined %}
slotConfiguration.m_dynamicGroup = AZ::Crc32("{{ Property.attrib['DynamicGroup'] }}");
{% endif %}
{% if Property.attrib['RestrictedTypes'] is defined %}
{% set typeContractList = Property.attrib['RestrictedTypes'].split(';') | join("(), ") %}
// Restricted Type Contract
slotConfiguration.m_contractDescs = AZStd::vector<ScriptCanvas::ContractDescriptor>{ { []() { return aznew ScriptCanvas::RestrictedTypeContract({ {{ typeContractList }}() }); } } };
{% endif %}
AddSlot(slotConfiguration);
}
{% endfor %}
}
bool {{ Class.attrib['QualifiedName'] }}::RequiresDynamicSlotOrdering() const
{
return {% if Class.attrib['DynamicSlotOrdering'] is defined and Class.attrib['DynamicSlotOrdering'] == "true" %}true{% else %}false{% endif %};
}
bool {{ Class.attrib['QualifiedName'] }}::IsDeprecated() const
{
return {% if Class.attrib['Deprecated'] is defined %}true{% else %}false{% endif %};
}
void {{ Class.attrib['QualifiedName'] }}::Reflect(AZ::ReflectContext* context)
{
{% if Class.attrib['DependentReflections'] is defined %}
{% for dependentClass in Class.attrib['DependentReflections'].split(';') %}
{{ dependentClass }}::Reflect(context);
{% endfor %}
{% endif %}
{% if Class.attrib['Base'] is defined %}
static_assert((std::is_base_of<ScriptCanvas::Node, {{ Class.attrib['Base'] }}>::value), "Script Canvas nodes require the first base class to be derived from ScriptCanvas::Node");
{% endif %}
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<{{ Class.attrib['QualifiedName'] }}{% if Class.attrib['Base'] is defined %}, {{ Class.attrib['Base'] }}{% endif %}>()
{% if Class.attrib['EventHandler'] is defined %}
->EventHandler<{{ Class.attrib['EventHandler'] }}>()
{% endif %}
{% if Class.attrib['Version'] is defined %}
->Version({{ Class.attrib['Version'] }}{% if Class.attrib['VersionConverter'] is defined %}, &{{ Class.attrib['VersionConverter'] }}{% endif %})
{% endif %}
{% for Property in Class.iter('SerializedProperty') %}
->Field("{{ Property.attrib['Name'] }}", &{{ Class.attrib['Name'] }}::{{ Property.attrib['Name'] | replace(' ','') }})
{% endfor %}
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<{{ Class.attrib['QualifiedName'] }}>("{{ Class.attrib['PreferredClassName'] }}", "{{ Class.attrib['Description'] }}")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
{% if Class.attrib['Category'] is defined %}
->Attribute(AZ::Edit::Attributes::Category, "{{ Class.attrib['Category'] }}")
{% endif %}
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
{% if Class.attrib['Icon'] is defined %}
->Attribute(AZ::Edit::Attributes::Icon, "{{ Class.attrib['Icon'] }}")
{% endif %}
{% if Class.attrib['Deprecated'] is defined %}
->Attribute(ScriptCanvas::Attributes::Node::TitlePaletteOverride, "DeprecatedNodeTitlePalette")
->Attribute(AZ::Script::Attributes::Deprecated, true)
{% else %}
{% if Class.attrib['EditAttributes'] is defined %}
{% for editAttributePair in Class.attrib['EditAttributes'].split(';') %}
{% set editAttributeKey, editAttributeValue = editAttributePair.split('@') %}
{% if editAttributeKey == "AZ::Script::Attributes::ExcludeFrom" %}
->Attribute({{ editAttributeKey }}, {{ editAttributeValue }})
{% else %}
->Attribute({{ editAttributeKey }}, "{{ editAttributeValue }}")
{% endif %}
{% endfor %}
{% endif %}
{% for Property in Class.iter('EditProperty') %}
{% if Property.attrib['SerializeProperty'] is defined %}
->DataElement({{ Property.attrib['UiHandler'] }}, &{{ Class.attrib['Name'] }}::{{ Property.attrib['SerializeProperty'] }}, "{{ Property.attrib['SerializeProperty'] }}", "")
{% else %}
->DataElement({{ Property.attrib['UiHandler'] }}, &{{ Class.attrib['Name'] }}::{{ Property.attrib['FieldName'] }}, "{{ Property.attrib['Name'] | replace(' ','') }}", {% if Property.attrib['Description'] is defined %}"{{ Property.attrib['Description'] }}" {% else %}""{% endif %})
{% endif %}
{% for EditAttribute in Property.iter('EditAttribute') %}
->Attribute({{ EditAttribute.attrib['Key'] }}, {{ EditAttribute.attrib['Value'] }})
{% endfor %}
{% endfor %}
{% endif %}
;
}
}
}
{# Property Getters #}
{% for Property in Class.iter('Property') %}
{{ Property.attrib['Type'] }} {{ Class.attrib['Name'] }}Property::Get{{ Property.attrib['Name'] | replace(' ','') }}(ScriptCanvas::Node* owner)
{
ScriptCanvas::SlotId slotId = Get{{ Property.attrib['Name'] | replace(' ','') }}SlotId(owner);
const ScriptCanvas::Datum* datum = owner->FindDatum(slotId);
if (!datum)
{
AZ_Error("Script Canvas", false, "Cannot find generated code gen slot with name {{ Property.attrib['Name'] | replace(' ','') }}. Has the ScriptCanvas_Property::Name changed without writing a version converter");
}
const {{ Property.attrib['Type'] }}* datumValue = datum ? datum->GetAs<{{ Property.attrib['Type'] }}>() : nullptr;
return datumValue ? *datumValue : {{ Property.attrib['Type'] }}();
}
{% endfor %}
{% endfor %}
{% endfor %}
@@ -0,0 +1,476 @@
/*
* 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
/*
*
* This file contains the AzCodeGenerator tag definitions for Script Canvas, it also provides the necessary
* documentation for the usage of the different code generation tags and the intellisense helpers for
* supported tags.
*
* CodeGen in Script Canvas consists of two parts, the first part is the header, nodes that use any of the
* code generation tags in this file need to include the generated header file which will have the
* format: <filename>.generated.h
*
* The generated header file is used to perform code injection into the class definition, see: ScriptCanvas_Node
*
* Example:
* #include <Libraries/Core/Print.generated.h>
*
* The .cpp file will also need to include the generated code. This file will contain the generated serialization
* and reflection code for any of the tags specified in the class declaration.
*
* Example:
* #include <Libraries/Core/Print.generated.cpp>
*
*/
#include <AzCore/Preprocessor/CodeGen.h>
#include <AzCore/Serialization/EditContextConstants.inl>
#include <ScriptCanvas/Data/Data.h>
#include <ScriptCanvas/Core/Contract.h>
#include <ScriptCanvas/Core/SlotConfigurations.h>
#if !defined(AZ_CODE_GENERATOR)
/* ----------------------------------------------------------------------------------------------------------
*
* ScriptCanvas_Node
* This tag must be included within the body of any custom Script Canvas node.It generates the necessary code to support nodes
* and customizes the serialization and reflection parameters(version, converter).
*
* Supports:
* ScriptCanvas_Node::Uuid // REQUIRED Uuid for this node's type, it is used by the AZ_COMPONENT macro internally.
* ScriptCanvas_Node::Description // The friendly description to display in the editor (the name will be the name of the class)
* ScriptCanvas_Node::Icon // Attribute used by the EditContext to provide a path to an icon for the node.
* ScriptCanvas_Node::Version // The version of the node, this ensure data serialization versioning is supported
* // Optionally, the version tag supports a version converter, this can be used by
* // specifying the unqualified function name as the second argument of the Version tag.
* ScriptCanvas_Node::GraphEntryPoint // Some nodes need to execute as soon as the graph is activated (i.e. the Start node).
*
* Example:
* ScriptCanvas_Node(Print, ScriptCanvas_Node::Uuid("{085CBDD3-D4E0-44D4-BF68-8732E35B9DF1}")
* ScriptCanvas_Node::Description("Prints a string")
* ScriptCanvas_Node::Icon("Editor/Icons/ScriptCanvas/Print.png")
* ScriptCanvas_Node::Version(3, VersionConverter));
*
* ----------------------------------------------------------------------------------------------------------- */
#define ScriptCanvas_Node(ClassName, ...) AZ_JOIN(AZ_GENERATED_, ClassName)
/* ----------------------------------------------------------------------------------------------------------
*
* ScriptCanvas_In
* This tag provides a named "Input" execution slot to the node.
*
* Supports:
* ScriptCanvas_In::Name // The friendly name and description to display in the editor
*
* Example:
* ScriptCanvas_In(ScriptCanvas_In::Name("Start Process", "Signals this node to begin processing."));
*
* ----------------------------------------------------------------------------------------------------------- */
#define ScriptCanvas_In(...)
/* -----------------------------------------------------------------------------------------------------------
*
* ScriptCanvas_Out
* This tag provides a named "Output" execution slot to the node.
*
* Supports:
* ScriptCanvas_Out::Name // The friendly name and description to display in the editor
*
* Example:
* ScriptCanvas_Out(ScriptCanvas_Out::Name("On Finished", "Will be signaled when the operation is complete."));
*
* ---------------------------------------------------------------------------------------------------------- */
#define ScriptCanvas_Out(...)
/* -----------------------------------------------------------------------------------------------------------
*
* ScriptCanvas_OutLatent
* This tag provides a named latent out execution slot to the node.
*
* Supports:
* ScriptCanvas_OutLatent::Name // The friendly name and description to display in the editor
*
* Example:
* ScriptCanvas_OutLatent(ScriptCanvas_OutLatent::Name("On Finished", "Will be signaled when the operation is complete."));
*
* ---------------------------------------------------------------------------------------------------------- */
#define ScriptCanvas_OutLatent(...)
/*
*----------------------------------------------------------------------------------------------------------
*
* ScriptCanvas_Property
* This tag must precede a member variable in the class that you wish to expose to Script Canvas for editing
* and scripting. By default the property will be exposed with an input and output slot, but it can be customized
* to only expose one or the other through the Input/Output attributes.
*
* Usage:
*
* ScriptCanvas_Property(<property type>, <codegen attributes>);
*
* Supports:
* ScriptCanvas_Property::Name // The friendly name and description to display in the editor
* ScriptCanvas_Property::Input // Exposes this property as an INPUT slot on the node.
* ScriptCanvas_Property::Output // Exposes this property as an OUTPUT slot on the node.
* ScriptCanvas_Property::Transient // Property will not be reflected for serialization, edit or behavior, these properties are useful when the value can only be provided by an connected node.
*
* Examples:
*
* ScriptCanvas_Property(AZStd::string, ScriptCanvas_Property::Name("Text", "A string of characters"))
*
* ScriptCanvas_Property(bool, ScriptCanvas_Property::Name("Is Ready", "Returns true if the entity is ready.") ScriptCanvas_Property::Output)
*
* ScriptCanvas_Property(bool, ScriptCanvas_Property::Name("Enable", "Set whether this functionality is enabled.") ScriptCanvas_Property::Input)
*
* ---------------------------------------------------------------------------------------------------------- */
#define ScriptCanvas_Property(...)
/*
*----------------------------------------------------------------------------------------------------------
*
* ScriptCanvas_DynamicDataSlot
*
* This tag must precede a definition of a Dynamically Typed slot.
*
* Usage:
*
* ScriptCanvas_DynamicDataSlot(<Dynamic PropertyType>, <ConnectionType>, <codegen attributes>);
* Supports:
* ScriptCanvas_Property::Name // The friendly name and description to display in the editor
* ScriptCanvas_Property::DynamicGroup // A way of grouping multiple dynamically typed slots to all have the same type.
*
*
* Examples:
*
* ScriptCanvas_DynamicProperty(ScriptCanvas::DynamicDataType::Value, ScriptCanvas::ConnectionType::Input, ScriptCanvas_Property::Name("Value", "A generic value"))*
* ScriptCanvas_DynamicProperty(ScriptCanvas::DynamicDataType::Any, ScriptCanvas::ConnectionType::Output, ScriptCanvas_Property::Name("Any", "A generic any"))
* ScriptCanvas_DynamicProperty(ScriptCanvas::DynamicDataType::Container, ScriptCanvas_Property::Input, ScriptCanvas_Property::Name("Container", "A Generic Container Input"))*
*/
#define ScriptCanvas_DynamicDataSlot(DynamicDataType, ConnectionType, ...)
/*
*----------------------------------------------------------------------------------------------------------
*
* Property
* This tag provides a mechanism to reflect a property to the serialization context that does not
* need to be an editable or an input property.
*
* Examples:
*
* Property(bool, m_autoConnect);
*
*
* ---------------------------------------------------------------------------------------------------------- */
#define ScriptCanvas_SerializeProperty(Type, Name, ...) Type Name;
/*
*----------------------------------------------------------------------------------------------------------
*
* Property
* This is the same as ScriptCanvas_SerializeProperty, but allows a user to provide a default value for the property
*
* Examples:
*
* ScriptCanvas_SerializePropertyWithDefaults(bool, m_autoConnect, false);
*
*
* ---------------------------------------------------------------------------------------------------------- */
#define ScriptCanvas_SerializePropertyWithDefaults(Type, Name, DefaultVal, ...) Type Name{ DefaultVal };
/*
*----------------------------------------------------------------------------------------------------------
*
* EditProperty
* This tag provides a mechanism to reflect a property to the serialization context and reflect it to
* the EditContext with EditContext attribute support.
*
* Examples:
*
* EditProperty(bool, m_autoConnect, EditProperty::Name("Auto Connect", "When true it will auto connect to the graph entity."));
*
* ---------------------------------------------------------------------------------------------------------- */
#define ScriptCanvas_EditProperty(Type, Name, ...) Type Name;
/*
*----------------------------------------------------------------------------------------------------------
*
* EditProperty
* This is the same tag as ScriptCanvas_EditProperty, but allows the user to provide a default value to the property
*
* Examples:
*
* ScriptCanvas_EditPropertyWithDefaults(bool, m_autoConnect, false EditProperty::Name("Auto Connect", "When true it will auto connect to the graph entity."));
*
* ---------------------------------------------------------------------------------------------------------- */
#define ScriptCanvas_EditPropertyWithDefaults(Type, Name, DefaultVal, ...) Type Name{ DefaultVal };
/*
*----------------------------------------------------------------------------------------------------------
*
* ScriptCanvas_PropertyWithDefaults
* This is the same tag as ScriptCanvas_Property but it gives the user the ability to provide and override
* the default value for the property.
*
* Example:
*
* ScriptCanvas_PropertyWithDefaults(AZ::Vector2, AZ::Vector2(20.f, 20.f),
* ScriptCanvas_Property::Name("Position", "Position of the text on-screen in normalized coordinates [0-1].")
* ScriptCanvas_Property::Input);
*
* ---------------------------------------------------------------------------------------------------------- */
#define ScriptCanvas_PropertyWithDefaults(...)
/*
*----------------------------------------------------------------------------------------------------------
*
* ScriptCanvas_Include
*
* When it is necessary for the generated file to contain a specific include.
* Note: The include directive will use the brackets syntax. (e.g. ScriptCanvas_Include("AzCore/Script/ScriptTimePoint.h")
* will produce:
* #include <AzCore/Script/ScriptTimePoint.h>
* in the generated.h file
* ---------------------------------------------------------------------------------------------------------- */
#define ScriptCanvas_Include(IncludeDeclaration, ...)
#else
// These are the tag definitions as seen by AzCodeGenerator during code traversal, they will produce the necessary
// data for the code generation templates to produce code. See: ScriptCanvas/CodeGen/Drivers
#define ScriptCanvas_Node(ClassName, ...) AZCG_CreateArgumentAnnotation(ScriptCanvas_Class, Class_Attribute, Identifier(ClassName), __VA_ARGS__) int AZ_JOIN(m_azCodeGenInternal, __COUNTER__);
#define ScriptCanvas_In(...) AZCG_CreateArgumentAnnotation(ScriptCanvas_In, Identifier(In), __VA_ARGS__) int AZ_JOIN(m_azCodeGenInternal, __COUNTER__);
#define ScriptCanvas_Out(...) AZCG_CreateArgumentAnnotation(ScriptCanvas_Out, Identifier(Out), __VA_ARGS__) int AZ_JOIN(m_azCodeGenInternal, __COUNTER__);
#define ScriptCanvas_OutLatent(...) AZCG_CreateArgumentAnnotation(ScriptCanvas_OutLatent, Identifier(Out), __VA_ARGS__) int AZ_JOIN(m_azCodeGenInternal, __COUNTER__);
#define ScriptCanvas_Property(Type, ...) AZCG_CreateArgumentAnnotation(ScriptCanvas_Property, Identifier(Property), ValueType(Type), __VA_ARGS__) Type AZ_JOIN(m_azCodeGenInternal, __COUNTER__);
#define ScriptCanvas_PropertyWithDefaults(Type, Default, ...) AZCG_CreateArgumentAnnotation(ScriptCanvas_Property, Identifier(Property), ValueType(Type), DefaultValue(AZ_STRINGIZE(Default)), __VA_ARGS__) Type AZ_JOIN(m_azCodeGenInternal, __COUNTER__);
#define ScriptCanvas_DynamicDataSlot(DynamicDataType, ConnectionDirectionType, ...) AZCG_CreateArgumentAnnotation(ScriptCanvas_DynamicDataSlot, Identifier(DynamicDataSlot), DynamicType(DynamicDataType), ConnectionType(ConnectionDirectionType), __VA_ARGS__) Type AZ_JOIN(m_azCodeGenlInternal, __COUNTER__);
#define ScriptCanvas_SerializeProperty(Type, Name, ...) AZCG_CreateArgumentAnnotation(ScriptCanvas_SerializeProperty, SerializedProperty, __VA_ARGS__) Type Name;
#define ScriptCanvas_EditProperty(Type, Name, ...) AZCG_CreateArgumentAnnotation(ScriptCanvas_SerializeProperty, SerializedProperty, EditProperty, __VA_ARGS__) Type Name;
#define ScriptCanvas_SerializePropertyWithDefaults(Type, Name, DefaultVal, ...) AZCG_CreateArgumentAnnotation(ScriptCanvas_SerializeProperty, SerializedProperty, __VA_ARGS__) Type Name{ DefaultVal };
#define ScriptCanvas_EditPropertyWithDefaults(Type, Name, DefaultVal, ...) AZCG_CreateArgumentAnnotation(ScriptCanvas_SerializeProperty, SerializedProperty, EditProperty, __VA_ARGS__) Type Name{ DefaultVal };
#define ScriptCanvas_Include(IncludeDeclaration, ...) AZCG_CreateArgumentAnnotation(ScriptCanvas_Includes, Identifier(IncludeDeclaration), __VA_ARGS__) int AZ_JOIN(m_azCodeGenInternal, __COUNTER__);
#endif
// Intellisense helpers, the following definitions exist to provide code completion details regarding what attributes are
// supported by the different tags.
// Note: It's important to verify these definitions exist within your templates:
// {% if class.annotations.ScriptCanvas_Node is defined %}
// Tags that might be common to multiple contexts, should be aliased into those namespaces and not used directly
namespace ScriptCanvasTags
{
struct Name
{
Name([[maybe_unused]] const char* name, [[maybe_unused]] const char* description) {}
};
struct Description
{
Description([[maybe_unused]] const char* description) {}
};
struct Uuid
{
Uuid([[maybe_unused]] const char* uuid) {}
};
struct Category
{
Category([[maybe_unused]] const char* category) {}
};
struct DisplayGroup
{
DisplayGroup([[maybe_unused]] const char* displayGroup) {}
};
struct Icon
{
Icon([[maybe_unused]] const char* icon) {}
};
struct Version
{
using ConverterFunction = bool(class AZ::SerializeContext& context, class AZ::SerializeContext::DataElementNode& classElement);
Version([[maybe_unused]] unsigned int version) {}
Version([[maybe_unused]] unsigned int version, [[maybe_unused]] ConverterFunction converter) {}
};
template <class EventHandlerType>
struct EventHandler
{
EventHandler() = default;
};
namespace Edit
{
struct UIHandler
{
UIHandler([[maybe_unused]] const AZ::Crc32& uiHandler = AZ::Edit::UIHandlers::Default) {}
};
}
struct EditAttributes
{
template <typename ...Args>
EditAttributes(Args&&... args) {}
};
struct BaseClass
{
BaseClass(AZStd::initializer_list<const char*>) {}
};
// Provided a hook for reflecting dependent classes from a node.
struct DependentReflections
{
DependentReflections(AZStd::initializer_list<const char*>) {}
};
struct Deprecated
{
Deprecated([[maybe_unused]] const char* details) {}
};
struct Contracts
{
explicit Contracts([[maybe_unused]] AZStd::initializer_list<ScriptCanvas::Contract> contracts) {}
};
struct RestrictedTypeContractTag
{
explicit RestrictedTypeContractTag([[maybe_unused]] AZStd::initializer_list<ScriptCanvas::Data::Type> restrictedType) {}
};
struct SupportsMethodContractTag
{
explicit SupportsMethodContractTag([[maybe_unused]] const char* methodName) {}
};
}
namespace ScriptCanvas_Node
{
using ScriptCanvasTags::Name;
using ScriptCanvasTags::Description;
using ScriptCanvasTags::Uuid;
using ScriptCanvasTags::Icon;
using ScriptCanvasTags::Version;
using ScriptCanvasTags::EventHandler;
using ScriptCanvasTags::EditAttributes;
using ScriptCanvasTags::Category;
using ScriptCanvasTags::Deprecated;
using ScriptCanvasTags::DependentReflections;
struct GraphEntryPoint
{
GraphEntryPoint(bool) {}
};
// Signals whether or not the ordering of dynamically added slots on the node will change during edit time.
//
// Main use cases are for user input that will add/remove slots where order is desired to be maintained
struct DynamicSlotOrdering
{
DynamicSlotOrdering(bool) {}
};
}
namespace ScriptCanvas_In
{
using ScriptCanvasTags::Name;
using ScriptCanvasTags::DisplayGroup;
using ScriptCanvasTags::Contracts;
}
namespace ScriptCanvas_Out
{
using ScriptCanvasTags::Name;
using ScriptCanvasTags::DisplayGroup;
}
namespace ScriptCanvas_OutLatent
{
using ScriptCanvasTags::Name;
using ScriptCanvasTags::DisplayGroup;
}
namespace ScriptCanvas_Property
{
using ScriptCanvasTags::Name;
using ScriptCanvasTags::DisplayGroup;
using ScriptCanvasTags::Edit::UIHandler;
using AzCommon::Attributes::ChangeNotify;
using AzCommon::Attributes::Visibility;
using AzCommon::Attributes::AutoExpand;
using AzCommon::Attributes::DescriptionTextOverride;
using AzCommon::Attributes::NameLabelOverride;
using AzCommon::Attributes::Min;
using AzCommon::Attributes::Max;
// Will produce an untyped input slot.
using Overloaded = bool;
// Exposes this property as an INPUT slot on the node.
using Input = bool;
// Exposes this property as an OUTPUT slot on the node.
using Output = bool;
// Transient properties will not be reflected for serialization, edit or behavior, these are properties whose
// value will be provided by a connected node.
using Transient = bool;
using OutputStorageSpec = bool;
}
namespace ScriptCanvas_DynamicDataSlot
{
using ScriptCanvasTags::Name;
using ScriptCanvasTags::DisplayGroup;
using ScriptCanvasTags::Contracts;
using ScriptCanvasTags::RestrictedTypeContractTag;
using ScriptCanvasTags::SupportsMethodContractTag;
using DynamicGroup = AZStd::string;
}
namespace EditProperty
{
using ScriptCanvasTags::Name;
using ScriptCanvasTags::Category;
using ScriptCanvasTags::EditAttributes;
using AzCommon::Attributes::ChangeNotify;
using AzCommon::Attributes::Visibility;
using AzCommon::Attributes::AutoExpand;
using AzCommon::Attributes::DescriptionTextOverride;
using AzCommon::Attributes::NameLabelOverride;
using AzCommon::Attributes::Min;
using AzCommon::Attributes::Max;
}
@@ -0,0 +1,61 @@
/*
* 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
namespace ScriptCanvas
{
namespace Attributes
{
namespace Slot
{
const static AZ::Crc32 Type = AZ_CRC("SlotType", 0x53811c3e);
}
namespace Node
{
const static AZ::Crc32 TitlePaletteOverride = AZ_CRC("TitlePaletteOverride", 0x2faad537);
//! ScriptCanvas needs to know whether some nodes should be executed as soon as the graph is
//! activated. This is the case of the OnGraphStart event, but it's valid for any nodes
//! that need to process without an explicit execution in signal.
const static AZ::Crc32 GraphEntryPoint = AZ_CRC("ScriptCanvasGraphEntryPoint", 0xa3702458);
const static AZ::Crc32 NodeType = AZ_CRC("ScriptCanvasNodeType", 0xfe591c34);
}
namespace UIHandlers
{
const static AZ::Crc32 GenericLineEdit = AZ_CRC("GenericLineEdit", 0xf6133796);
}
namespace NodePalette
{
// Attribute that can be used to store a function which creates a custom NodePaletteTreeItem
const static AZ::Crc32 TreeItemOverride = AZ_CRC("TreeItemOverride", 0xd457505c);
}
const static AZ::Crc32 StringToProperty = AZ_CRC("StringToProperty", 0x3e76c0a2);
const static AZ::Crc32 PropertyToString = AZ_CRC("PropertyToString", 0x323fc400);
const static AZ::Crc32 Input = AZ_CRC("Input", 0xd82832d7);
const static AZ::Crc32 Output = AZ_CRC("Output", 0xccde149e);
const static AZ::Crc32 Setter = AZ_CRC("Setter", 0x7c825e44);
const static AZ::Crc32 Getter = AZ_CRC("Getter", 0xe4c51ec9);
const static AZ::Crc32 AutoExpose = AZ_CRC("AutoExpose", 0xb29a8440);
const static AZ::Crc32 Contract = AZ_CRC("Contract", 0xe98f2859);
const static AZ::Crc32 AllowSetterSlot = AZ_CRC("AllowSetterSlot", 0xfe7e175b);
const static AZ::Crc32 AllowGetterSlot = AZ_CRC("AllowGetterSlot", 0xd03b36c9);
const static AZ::Crc32 ShowSetterByDefault = AZ_CRC("ShowSetterByDefault", 0x482bc9f4);
const static AZ::Crc32 ShowGetterByDefault = AZ_CRC("ShowGetterByDefault", 0x863533d8);
}
}
@@ -0,0 +1,179 @@
/*
* 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 "Connection.h"
#include "Slot.h"
#include "Node.h"
#include "NodeBus.h"
#include <AzCore/Serialization/SerializeContext.h>
namespace ScriptCanvas
{
AZ::Outcome<void, AZStd::string> MatchContracts(const Slot& firstSlot, const Slot& secondSlot)
{
AZ::Outcome<void, AZStd::string> outcome = AZ::Success();
AZStd::string failedContract;
AZStd::all_of(firstSlot.GetContracts().begin(), firstSlot.GetContracts().end(), [&firstSlot, &secondSlot, &outcome](const AZStd::unique_ptr<Contract>& contract)
{
outcome = contract->Evaluate(firstSlot, secondSlot);
if (outcome.IsSuccess())
{
return true;
}
return false;
});
return outcome;
}
Connection::Connection(const ID& fromNode, const SlotId& fromSlot, const ID& toNode, const SlotId& toSlot)
: m_sourceEndpoint(fromNode, fromSlot)
, m_targetEndpoint(toNode, toSlot)
{
}
Connection::Connection(const Endpoint& fromConnection, const Endpoint& toConnection)
: m_sourceEndpoint(fromConnection)
, m_targetEndpoint(toConnection)
{
}
Connection::~Connection()
{
ConnectionRequestBus::Handler::BusDisconnect();
}
void Connection::Reflect(AZ::ReflectContext* reflection)
{
Endpoint::Reflect(reflection);
NamedEndpoint::Reflect(reflection);
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection);
if (serializeContext)
{
serializeContext->Class<Connection, AZ::Component>()
->Version(0)
->Field("sourceEndpoint", &Connection::m_sourceEndpoint)
->Field("targetEndpoint", &Connection::m_targetEndpoint)
;
}
}
void Connection::Init()
{
ConnectionRequestBus::Handler::BusConnect(GetEntityId());
}
void Connection::Activate()
{
}
void Connection::Deactivate()
{
}
AZ::Outcome<void, AZStd::string> Connection::ValidateEndpoints(const Endpoint& sourceEndpoint, const Endpoint& targetEndpoint)
{
Slot* sourceSlot{};
NodeRequestBus::EventResult(sourceSlot, sourceEndpoint.GetNodeId(), &NodeRequests::GetSlot, sourceEndpoint.GetSlotId());
Slot* targetSlot{};
NodeRequestBus::EventResult(targetSlot, targetEndpoint.GetNodeId(), &NodeRequests::GetSlot, targetEndpoint.GetSlotId());
if (!sourceSlot)
{
return AZ::Failure(AZStd::string("Source slot does not exist."));
}
if (!targetSlot)
{
return AZ::Failure(AZStd::string("Target slot does not exist."));
}
return ValidateConnection((*sourceSlot), (*targetSlot));
}
AZ::Outcome<void, AZStd::string> Connection::ValidateConnection(const Slot& sourceSlot, const Slot& targetSlot)
{
if (sourceSlot.IsData())
{
auto typeMatchCheck = sourceSlot.IsTypeMatchFor(targetSlot);
if (!typeMatchCheck)
{
return typeMatchCheck;
}
}
auto connectionSourceToTarget = MatchContracts(sourceSlot, targetSlot);
if (!connectionSourceToTarget.IsSuccess())
{
return connectionSourceToTarget;
}
auto connectionTargetToSource = MatchContracts(targetSlot, sourceSlot);
if (!connectionTargetToSource.IsSuccess())
{
return connectionTargetToSource;
}
return AZ::Success();
}
bool Connection::ContainsEndpoint(const Endpoint& endpoint)
{
return m_sourceEndpoint == endpoint
|| m_targetEndpoint == endpoint;
}
const SlotId& Connection::GetSourceSlot() const
{
return m_sourceEndpoint.GetSlotId();
}
const SlotId& Connection::GetTargetSlot() const
{
return m_targetEndpoint.GetSlotId();
}
const ID& Connection::GetTargetNode() const
{
return m_targetEndpoint.GetNodeId();
}
const ID& Connection::GetSourceNode() const
{
return m_sourceEndpoint.GetNodeId();
}
const Endpoint& Connection::GetTargetEndpoint() const
{
return m_targetEndpoint;
}
const Endpoint& Connection::GetSourceEndpoint() const
{
return m_sourceEndpoint;
}
void Connection::OnNodeRemoved(const ID& nodeId)
{
if (nodeId == m_sourceEndpoint.GetNodeId() || nodeId == m_targetEndpoint.GetNodeId())
{
GraphRequestBus::Event(*GraphNotificationBus::GetCurrentBusId(), &GraphRequests::DisconnectById, GetEntityId());
}
}
}
@@ -0,0 +1,78 @@
/*
* 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
#include <AzCore/Component/Component.h>
#include <AzCore/Outcome/Outcome.h>
#include "Core.h"
#include "ConnectionBus.h"
#include "GraphBus.h"
namespace ScriptCanvas
{
class Slot;
class Connection
: public AZ::Component
, protected ConnectionRequestBus::Handler
, protected GraphNotificationBus::Handler
{
public:
AZ_COMPONENT(Connection, "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB}", AZ::Component);
Connection() = default;
Connection(const ID& fromNode, const SlotId& fromSlot, const ID& toNode, const SlotId& toSlot);
Connection(const Endpoint& fromConnection, const Endpoint& toConnection);
virtual ~Connection();
static void Reflect(AZ::ReflectContext* reflection);
// AZ::Component
void Init() override;
void Activate() override;
void Deactivate() override;
static AZ::Outcome<void, AZStd::string> ValidateEndpoints(const Endpoint& sourceEndpoint, const Endpoint& targetEndpoint);
static AZ::Outcome<void, AZStd::string> ValidateConnection(const Slot& sourceSlot, const Slot& targetSlot);
bool ContainsEndpoint(const Endpoint& endpoint);
// ConnectionRequestBus
const SlotId& GetSourceSlot() const override;
const SlotId& GetTargetSlot() const override;
const ID& GetTargetNode() const override;
const ID& GetSourceNode() const override;
const Endpoint& GetTargetEndpoint() const override;
const Endpoint& GetSourceEndpoint() const override;
// GraphNotificationBus
void OnNodeRemoved(const ID& nodeId) override;
protected:
//-------------------------------------------------------------------------
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("ScriptCanvasConnectionService", 0x028dc06e));
}
Endpoint m_sourceEndpoint;
Endpoint m_targetEndpoint;
};
}
@@ -0,0 +1,40 @@
/*
* 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
#include "Core.h"
#include "Endpoint.h"
#include <AzCore/EBus/EBus.h>
namespace ScriptCanvas
{
class ConnectionRequests :
public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = AZ::EntityId;
virtual const SlotId& GetTargetSlot() const = 0;
virtual const SlotId& GetSourceSlot() const = 0;
virtual const AZ::EntityId& GetTargetNode() const = 0;
virtual const AZ::EntityId& GetSourceNode() const = 0;
virtual const Endpoint& GetTargetEndpoint() const = 0;
virtual const Endpoint& GetSourceEndpoint() const = 0;
};
using ConnectionRequestBus = AZ::EBus<ConnectionRequests>;
}
@@ -0,0 +1,46 @@
/*
* 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 "Contract.h"
#include "ContractBus.h"
#include "Slot.h"
#include <ScriptCanvas/Data/Data.h>
namespace ScriptCanvas
{
void Contract::Reflect(AZ::ReflectContext* reflection)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection);
if (serializeContext)
{
serializeContext->Class<Contract>()
->Version(0)
;
}
}
AZ::Outcome<void, AZStd::string> Contract::Evaluate(const Slot& sourceSlot, const Slot& targetSlot) const
{
return OnEvaluate(sourceSlot, targetSlot);
}
AZ::Outcome<void, AZStd::string> Contract::EvaluateForType(const Data::Type& dataType) const
{
if (!dataType.IsValid())
{
return AZ::Failure<AZStd::string>("No valid contract match for Invalid Data Type");
}
return OnEvaluateForType(dataType);
}
}
@@ -0,0 +1,76 @@
/*
* 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
#include <AzCore/std/string/string.h>
#include <AzCore/Outcome/Outcome.h>
#include <AzCore/std/functional.h>
#include <AzCore/Outcome/Outcome.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/RTTI/RTTI.h>
namespace AZ
{
class ReflectContext;
}
namespace ScriptCanvas
{
class Slot;
class Contract;
namespace Data
{
class Type;
}
//! Function which will be invoked when a slot is created to allow the creation of a slot contract object
using ContractCreationFunction = AZStd::function<Contract*()>;
struct ContractDescriptor
{
AZ_CLASS_ALLOCATOR(ContractDescriptor, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(ContractDescriptor, "{C0E3537F-5E6A-4269-A717-17089559F7A1}");
ContractCreationFunction m_createFunc;
ContractDescriptor() = default;
ContractDescriptor(ContractCreationFunction&& createFunc)
: m_createFunc(AZStd::move(createFunc))
{}
};
class Contract
{
public:
AZ_CLASS_ALLOCATOR(Contract, AZ::SystemAllocator, 0);
AZ_RTTI(Contract, "{93846E60-BD7E-438A-B970-5C4AA591CF93}");
Contract() = default;
virtual ~Contract() = default;
static void Reflect(AZ::ReflectContext* reflection);
AZ::Outcome<void, AZStd::string> Evaluate(const Slot& sourceSlot, const Slot& targetSlot) const;
AZ::Outcome<void, AZStd::string> EvaluateForType(const Data::Type& dataType) const;
protected:
virtual AZ::Outcome<void, AZStd::string> OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const = 0;
// By default accept all Data::Types for each contract
// Mainly here for legacy support new contracts should implement this themselves.
virtual AZ::Outcome<void, AZStd::string> OnEvaluateForType(const Data::Type& dataType) const
{
AZ_UNUSED(dataType);
return AZ::Success();
};
};
}
@@ -0,0 +1,42 @@
/*
* 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
#include "Core.h"
#include <AzCore/EBus/EBus.h>
namespace ScriptCanvas
{
class Contract;
class Slot;
namespace Data
{
class Type;
}
class ContractEvents : public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
//////////////////////////////////////////////////////////////////////////
virtual void OnValidContract(const Contract*, const Slot&, const Slot&) = 0;
virtual void OnInvalidContract(const Contract*, const Slot&, const Slot&) = 0;
};
using ContractEventBus = AZ::EBus<ContractEvents>;
}
@@ -0,0 +1,23 @@
/*
* 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
#include "Contracts/ConnectionLimitContract.h"
#include "Contracts/ContractRTTI.h"
#include "Contracts/DisallowReentrantExecutionContract.h"
#include "Contracts/DisplayGroupConnectedSlotLimitContract.h"
#include "Contracts/DynamicTypeContract.h"
#include "Contracts/SlotTypeContract.h"
#include "Contracts/TypeContract.h"
#include "Contracts/IsReferenceTypeContract.h"
#include "Contracts/SupportsMethodContract.h"
#include "Contracts/MathOperatorContract.h"
@@ -0,0 +1,70 @@
/*
* 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 "ConnectionLimitContract.h"
#include <ScriptCanvas/Core/ContractBus.h>
#include <ScriptCanvas/Core/GraphBus.h>
#include <ScriptCanvas/Core/NodeBus.h>
#include <ScriptCanvas/Core/Endpoint.h>
#include <ScriptCanvas/Core/Slot.h>
#include <ScriptCanvas/Core/Node.h>
#include <ScriptCanvas/Core/Graph.h>
namespace ScriptCanvas
{
AZ::Outcome<void, AZStd::string> ConnectionLimitContract::OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const
{
if (m_limit < 0)
{
return AZ::Success();
}
AZStd::vector<Endpoint> connectedEndpoints = sourceSlot.GetNode()->GetGraph()->GetConnectedEndpoints(sourceSlot.GetEndpoint());
if (connectedEndpoints.size() < static_cast<AZ::u32>(m_limit))
{
return AZ::Success();
}
else
{
AZStd::string errorMessage = AZStd::string::format
( "Connection cannot be created between source slot \"%s\" and target slot \"%s\" as the source slot has a Connection Limit of %d. (%s)"
, sourceSlot.GetName().data()
, targetSlot.GetName().data()
, m_limit
, RTTI_GetTypeName());
return AZ::Failure(errorMessage);
}
}
ConnectionLimitContract::ConnectionLimitContract(AZ::s32 limit)
: m_limit(AZStd::GetMax(-1, limit))
{}
void ConnectionLimitContract::SetLimit(AZ::s32 limit)
{
m_limit = AZStd::GetMax(-1, limit);
}
void ConnectionLimitContract::Reflect(AZ::ReflectContext* reflection)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection);
if (serializeContext)
{
serializeContext->Class<ConnectionLimitContract, Contract>()
->Version(0)
->Field("limit", &ConnectionLimitContract::m_limit)
;
}
}
}
@@ -0,0 +1,38 @@
/*
* 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
#include <ScriptCanvas/Core/Contract.h>
#include <ScriptCanvas/Data/Data.h>
namespace ScriptCanvas
{
class ConnectionLimitContract
: public Contract
{
public:
AZ_CLASS_ALLOCATOR(ConnectionLimitContract, AZ::SystemAllocator, 0);
AZ_RTTI(ConnectionLimitContract, "{C66FB68F-63D5-4EE2-BC28-D566EC2E5159}", Contract);
ConnectionLimitContract(AZ::s32 limit = -1);
~ConnectionLimitContract() override = default;
static void Reflect(AZ::ReflectContext* reflection);
void SetLimit(AZ::s32 limit);
protected:
AZ::s32 m_limit;
AZ::Outcome<void, AZStd::string> OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const override;
};
}
@@ -0,0 +1,84 @@
/*
* 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 "ContractRTTI.h"
#include <Core/ContractBus.h>
#include <Core/Node.h>
#include <Core/Slot.h>
namespace ScriptCanvas
{
AZ::Outcome<void, AZStd::string> ContractRTTI::OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const
{
AZ::Entity* nodeEntity{};
AZ::ComponentApplicationBus::BroadcastResult(nodeEntity, &AZ::ComponentApplicationRequests::FindEntity, targetSlot.GetNodeId());
const auto node = nodeEntity ? AZ::EntityUtils::FindFirstDerivedComponent<Node>(nodeEntity) : nullptr;
bool valid{};
if (m_flags == Inclusive)
{
if (node)
{
for (const auto& type : m_types)
{
if (node->RTTI_IsTypeOf(type))
{
valid = true;
break;
}
}
}
}
else
{
if (node)
{
valid = true;
for (const auto& type : m_types)
{
if (node->RTTI_IsTypeOf(type))
{
valid = false;
break;
}
}
}
}
if (valid)
{
return AZ::Success();
}
AZStd::string errorMessage = AZStd::string::format("Connection cannot be created between source slot \"%s\" and target slot \"%s\" as the types do not satisfy the RTTI requirement. (%s)"
, sourceSlot.GetName().data()
, targetSlot.GetName().data()
, RTTI_GetTypeName());
return AZ::Failure(errorMessage);
}
void ContractRTTI::Reflect(AZ::ReflectContext* reflection)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection);
if (serializeContext)
{
serializeContext->Class<ContractRTTI, Contract>()
->Version(1)
->Field("flags", &ContractRTTI::m_flags)
->Field("types", &ContractRTTI::m_types)
;
}
}
}
@@ -0,0 +1,62 @@
/*
* 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
#include <AzCore/std/containers/vector.h>
#include <ScriptCanvas/Core/Contract.h>
#include <ScriptCanvas/Data/Data.h>
namespace ScriptCanvas
{
class ContractRTTI
: public Contract
{
public:
AZ_CLASS_ALLOCATOR(ContractRTTI, AZ::SystemAllocator, 0);
AZ_RTTI(ContractRTTI, "{3CB87E9B-33A0-40B1-A7CC-72465814BEE6}", Contract);
enum Flags
{
Inclusive, //> Contract will be satisfied by any of the type Uuids stored in the contract.
Exclusive, //> Contract may satisfy any endpoint except to those types in the contract.
};
ContractRTTI(Flags flags = Inclusive) : m_flags(flags) {}
ContractRTTI(std::initializer_list<AZ::Uuid> types, Flags flags = Inclusive)
: ContractRTTI(types.begin(), types.end(), flags)
{}
template<typename Container>
ContractRTTI(const Container& types, Flags flags = Inclusive)
: ContractRTTI(types.begin(), types.end(), flags)
{}
template<typename InputIterator>
ContractRTTI(InputIterator first, InputIterator last, Flags flags = Inclusive)
: m_types(first, last)
, m_flags(flags)
{}
~ContractRTTI() override = default;
static void Reflect(AZ::ReflectContext* reflection);
void AddType(const AZ::Uuid& type) { m_types.push_back(type); }
protected:
Flags m_flags;
AZStd::vector<AZ::Uuid> m_types;
AZ::Outcome<void, AZStd::string> OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const override;
};
}
@@ -0,0 +1,47 @@
/*
* 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 "DisallowReentrantExecutionContract.h"
#include <ScriptCanvas/Core/ContractBus.h>
#include <ScriptCanvas/Core/Slot.h>
namespace ScriptCanvas
{
AZ::Outcome<void, AZStd::string> DisallowReentrantExecutionContract::OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const
{
bool valid = sourceSlot.GetNodeId() != targetSlot.GetNodeId();
if (valid)
{
return AZ::Success();
}
AZStd::string errorMessage = AZStd::string::format("Connection cannot be created between source slot \"%s\" and target slot \"%s\", this slot does not allow connections from the same node. (%s)"
, sourceSlot.GetName().data()
, targetSlot.GetName().data()
, RTTI_GetTypeName()
);
return AZ::Failure(errorMessage);
}
void DisallowReentrantExecutionContract::Reflect(AZ::ReflectContext* reflection)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection);
if (serializeContext)
{
serializeContext->Class<DisallowReentrantExecutionContract, Contract>()
->Version(0)
;
}
}
}
@@ -0,0 +1,34 @@
/*
* 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
#include <ScriptCanvas/Core/Contract.h>
namespace ScriptCanvas
{
class DisallowReentrantExecutionContract
: public Contract
{
public:
AZ_CLASS_ALLOCATOR(DisallowReentrantExecutionContract, AZ::SystemAllocator, 0);
AZ_RTTI(DisallowReentrantExecutionContract, "{8B476D16-D11C-4274-BE61-FA9B34BF54A3}", Contract);
DisallowReentrantExecutionContract() = default;
~DisallowReentrantExecutionContract() override = default;
static void Reflect(AZ::ReflectContext* reflection);
protected:
AZ::Outcome<void, AZStd::string> OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const override;
};
}
@@ -0,0 +1,79 @@
/*
* 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 "DisplayGroupConnectedSlotLimitContract.h"
#include <ScriptCanvas/Core/ContractBus.h>
#include <ScriptCanvas/Core/GraphBus.h>
#include <ScriptCanvas/Core/NodeBus.h>
#include <ScriptCanvas/Core/Endpoint.h>
#include <ScriptCanvas/Core/Slot.h>
#include <ScriptCanvas/Core/Node.h>
#include <ScriptCanvas/Core/Graph.h>
namespace ScriptCanvas
{
void DisplayGroupConnectedSlotLimitContract::Reflect(AZ::ReflectContext* reflection)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection);
if (serializeContext)
{
serializeContext->Class<DisplayGroupConnectedSlotLimitContract, Contract>()
->Version(0)
->Field("limit", &DisplayGroupConnectedSlotLimitContract::m_limit)
->Field("displayGroup", &DisplayGroupConnectedSlotLimitContract::m_displayGroup)
->Field("errorMessage", &DisplayGroupConnectedSlotLimitContract::m_customErrorMessage)
;
}
}
DisplayGroupConnectedSlotLimitContract::DisplayGroupConnectedSlotLimitContract(const AZStd::string& displayGroup, AZ::u32 connectedSlotLimit)
: m_displayGroup(displayGroup)
, m_limit(connectedSlotLimit)
{
}
AZ::Outcome<void, AZStd::string> DisplayGroupConnectedSlotLimitContract::OnEvaluate(const Slot& sourceSlot, [[maybe_unused]] const Slot& targetSlot) const
{
// If the slot is already connected, it can have more connections
if (sourceSlot.IsConnected())
{
return AZ::Success();
}
AZ::u32 connectionCount = 0;
AZStd::vector<Slot*> slotGroup = sourceSlot.GetNode()->GetSlotsWithDisplayGroup(m_displayGroup);
for (Slot* slot : slotGroup)
{
if (slot->IsConnected())
{
++connectionCount;
if (connectionCount >= m_limit)
{
AZStd::string errorMessage = m_customErrorMessage;
if (errorMessage.empty())
{
errorMessage = AZStd::string::format("Too many connections present for DisplayGroup - %s", m_displayGroup.c_str());
}
return AZ::Failure(errorMessage);
}
}
}
return AZ::Success();
}
}
@@ -0,0 +1,57 @@
/*
* 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
#include <ScriptCanvas/Core/Contract.h>
#include <ScriptCanvas/Data/Data.h>
namespace ScriptCanvas
{
// Limits the number of slots that can have connections within a given display group.
class DisplayGroupConnectedSlotLimitContract
: public Contract
{
public:
AZ_CLASS_ALLOCATOR(DisplayGroupConnectedSlotLimitContract, AZ::SystemAllocator, 0);
AZ_RTTI(DisplayGroupConnectedSlotLimitContract, "{71E55CC5-6212-48C2-973E-1AC9E20A4481}", Contract);
static void Reflect(AZ::ReflectContext* reflection);
DisplayGroupConnectedSlotLimitContract() = default;
DisplayGroupConnectedSlotLimitContract(const AZStd::string& displayGroup, AZ::u32 connectionLimit);
~DisplayGroupConnectedSlotLimitContract() override = default;
void SetDisplayGroup(const AZStd::string& displayGroup)
{
m_displayGroup = displayGroup;
}
void SetConnectionLimit(AZ::u32 connectionLimit)
{
m_limit = connectionLimit;
}
void SetCustomErrorMessage(const AZStd::string& customErrorMessage)
{
m_customErrorMessage = customErrorMessage;
}
protected:
AZStd::string m_displayGroup;
AZ::u32 m_limit = 0;
AZStd::string m_customErrorMessage;
AZ::Outcome<void, AZStd::string> OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const override;
};
}
@@ -0,0 +1,51 @@
/*
* 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 "DynamicTypeContract.h"
#include <ScriptCanvas/Core/ContractBus.h>
#include <ScriptCanvas/Core/Slot.h>
#include <ScriptCanvas/Core/Node.h>
namespace ScriptCanvas
{
AZ::Outcome<void, AZStd::string> DynamicTypeContract::OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const
{
Data::Type targetType = targetSlot.GetDataType();
bool acceptsType = sourceSlot.GetNode()->SlotAcceptsType(sourceSlot.GetId(), targetType);
if (acceptsType)
{
return AZ::Success();
}
AZStd::string errorMessage = AZStd::string::format("Connection cannot be created between source slot \"%s\" and target slot \"%s\", slot does not support type: %s."
, sourceSlot.GetName().data()
, targetSlot.GetName().data()
, Data::GetName(targetType).c_str()
);
return AZ::Failure(errorMessage);
}
void DynamicTypeContract::Reflect(AZ::ReflectContext* reflection)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
{
serializeContext->Class<DynamicTypeContract, Contract>()
->Version(0)
;
}
}
}
@@ -0,0 +1,32 @@
/*
* 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
#include <ScriptCanvas/Core/Contract.h>
namespace ScriptCanvas
{
class DynamicTypeContract
: public Contract
{
public:
AZ_CLASS_ALLOCATOR(DynamicTypeContract, AZ::SystemAllocator, 0);
AZ_RTTI(DynamicTypeContract, "{00822E5B-7DD0-4D52-B1A8-9CE9C1A5C4FB}", Contract);
~DynamicTypeContract() override = default;
static void Reflect(AZ::ReflectContext* reflection);
protected:
AZ::Outcome<void, AZStd::string> OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const override;
};
}
@@ -0,0 +1,61 @@
/*
* 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 "ExclusivePureDataContract.h"
#include <ScriptCanvas/Core/ContractBus.h>
#include <ScriptCanvas/Core/GraphBus.h>
#include <ScriptCanvas/Core/NodeBus.h>
#include <ScriptCanvas/Core/Endpoint.h>
#include <ScriptCanvas/Core/Slot.h>
namespace ScriptCanvas
{
AZ::Outcome<void, AZStd::string> ExclusivePureDataContract::HasNoPureDataConnection(const Slot& dataInputSlot) const
{
bool isOnPureDataThread(true);
NodeRequestBus::EventResult(isOnPureDataThread, dataInputSlot.GetNodeId(), &NodeRequests::IsOnPureDataThread, dataInputSlot.GetId());
if (!isOnPureDataThread)
{
return AZ::Success();
}
return AZ::Failure(AZStd::string("There is already a pure data input into this slot"));
}
AZ::Outcome<void, AZStd::string> ExclusivePureDataContract::OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const
{
if (sourceSlot.GetDescriptor().CanConnectTo(targetSlot.GetDescriptor()))
{
if (sourceSlot.GetDescriptor().IsInput())
{
return HasNoPureDataConnection(sourceSlot);
}
else if (targetSlot.GetDescriptor().IsInput())
{
return HasNoPureDataConnection(targetSlot);
}
}
return AZ::Failure(AZStd::string("invalid data connection attempted"));
}
void ExclusivePureDataContract::Reflect(AZ::ReflectContext* reflection)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
{
serializeContext->Class<ExclusivePureDataContract, Contract>()
->Version(0)
;
}
}
}
@@ -0,0 +1,35 @@
/*
* 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
#include <ScriptCanvas/Core/Contract.h>
namespace ScriptCanvas
{
class ExclusivePureDataContract
: public Contract
{
public:
AZ_CLASS_ALLOCATOR(ExclusivePureDataContract, AZ::SystemAllocator, 0);
AZ_RTTI(ExclusivePureDataContract, "{E48A0B26-B6B7-4AF3-9341-9E5C5C1F0DE8}", Contract);
// no multiple literals, variables, defaults, gets, or any other new form of data that can be routed without getting pushed by execution
~ExclusivePureDataContract() override = default;
static void Reflect(AZ::ReflectContext* reflection);
protected:
AZ::Outcome<void, AZStd::string> OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const override;
AZ::Outcome<void, AZStd::string> HasNoPureDataConnection(const Slot& dataInputSlot) const;
};
}
@@ -0,0 +1,62 @@
/*
* 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 "IsReferenceTypeContract.h"
#include <ScriptCanvas/Core/ContractBus.h>
#include <ScriptCanvas/Core/NodeBus.h>
#include <ScriptCanvas/Core/Slot.h>
namespace ScriptCanvas
{
AZ::Outcome<void, AZStd::string> IsReferenceTypeContract::OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const
{
Data::Type targetType = targetSlot.GetDataType();
if (EvaluateForType(targetType))
{
return AZ::Success();
}
AZStd::string errorMessage = AZStd::string::format("Connection cannot be created between source slot \"%s\" and target slot \"%s\", slot type must be a reference type, but is: %s."
, sourceSlot.GetName().data()
, targetSlot.GetName().data()
, Data::GetName(targetType).c_str()
);
return AZ::Failure(errorMessage);
}
AZ::Outcome<void, AZStd::string> IsReferenceTypeContract::OnEvaluateForType(const Data::Type& dataType) const
{
if (!Data::IsValueType(dataType))
{
return AZ::Success();
}
AZStd::string errorMessage = AZStd::string::format("Type %s is not a reference type."
, Data::GetName(dataType).c_str()
);
return AZ::Failure(errorMessage);
}
void IsReferenceTypeContract::Reflect(AZ::ReflectContext* reflection)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
{
serializeContext->Class<IsReferenceTypeContract, Contract>()
->Version(0)
;
}
}
}
@@ -0,0 +1,33 @@
/*
* 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
#include <ScriptCanvas/Core/Contract.h>
namespace ScriptCanvas
{
class IsReferenceTypeContract
: public Contract
{
public:
AZ_CLASS_ALLOCATOR(IsReferenceTypeContract, AZ::SystemAllocator, 0);
AZ_RTTI(IsReferenceTypeContract, "{7BBA9F9A-AABF-458F-B5D6-B7CCDC8C9BE6}", Contract);
~IsReferenceTypeContract() override = default;
static void Reflect(AZ::ReflectContext* reflection);
protected:
AZ::Outcome<void, AZStd::string> OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const override;
AZ::Outcome<void, AZStd::string> OnEvaluateForType(const Data::Type& dataType) const override;
};
}
@@ -0,0 +1,124 @@
/*
* 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 "MathOperatorContract.h"
#include <ScriptCanvas/Core/Slot.h>
#include <ScriptCanvas/Core/Node.h>
namespace ScriptCanvas
{
void MathOperatorContract::SetSupportedNativeTypes(const AZStd::unordered_set< Data::Type >& nativeTypes)
{
m_supportedNativeTypes = nativeTypes;
}
void MathOperatorContract::SetSupportedOperator(AZStd::string_view operatorString)
{
m_supportedOperator = operatorString;
}
bool MathOperatorContract::HasOperatorFunction() const
{
return m_supportedOperator.empty();
}
AZ::Outcome<void, AZStd::string> MathOperatorContract::OnEvaluate([[maybe_unused]] const Slot& sourceSlot, const Slot& targetSlot) const
{
// Check that the type in the target slot is one of the built in math functions
AZ::Entity* targetSlotEntity{};
AZ::ComponentApplicationBus::BroadcastResult(targetSlotEntity, &AZ::ComponentApplicationRequests::FindEntity, targetSlot.GetNodeId());
auto dataNode = targetSlotEntity ? AZ::EntityUtils::FindFirstDerivedComponent<Node>(targetSlotEntity) : nullptr;
if (dataNode)
{
const Data::Type& dataType = dataNode->GetSlotDataType(targetSlot.GetId());
if (dataType == Data::Type::Invalid())
{
// For right now we don't want to let dynamic slots connect to each other since the updating mechanism
// doesn't work for passing along type updating.
if (targetSlot.IsDynamicSlot())
{
for (const auto& supportedDataType : m_supportedNativeTypes)
{
if (targetSlot.IsTypeMatchFor(supportedDataType))
{
return AZ::Success();
}
}
}
}
else
{
return EvaluateForType(dataType);
}
}
return AZ::Failure(AZStd::string("Unable to find Node for Target Slot"));
}
AZ::Outcome<void, AZStd::string> MathOperatorContract::OnEvaluateForType(const Data::Type& dataType) const
{
if (dataType != Data::Type::Invalid())
{
if (m_supportedNativeTypes.count(dataType) != 0)
{
// This supports math operators
return AZ::Success();
}
}
AZ::BehaviorContext* behaviorContext(nullptr);
AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationRequests::GetBehaviorContext);
if (!behaviorContext)
{
AZ_Assert(false, "A behavior context is required!");
return AZ::Failure(AZStd::string::format("No Behavior Context"));
}
// Finally if we're not sure if the type supports the operator, check if it has the operator's method
const AZ::TypeId azType = Data::ToAZType(dataType);
const auto classIter(behaviorContext->m_typeToClassMap.find(azType));
if (classIter == behaviorContext->m_typeToClassMap.end())
{
return AZ::Failure(AZStd::string::format("Behavior Context does not contain reflection for type provided: %s", azType.ToString<AZStd::string>().c_str()));
}
AZ::BehaviorClass* behaviorClass = classIter->second;
if (behaviorClass)
{
if (behaviorClass->m_methods.find(m_supportedOperator) != behaviorClass->m_methods.end())
{
return AZ::Success();
}
}
if (m_supportedOperator.empty())
{
return AZ::Failure(AZStd::string::format("%s is not on list of supported types for Math Operation.", ScriptCanvas::Data::GetName(dataType).c_str()));
}
return AZ::Failure(AZStd::string::format("%s does not support the method: %s", ScriptCanvas::Data::GetName(dataType).c_str(), m_supportedOperator.c_str()));
}
void MathOperatorContract::Reflect(AZ::ReflectContext* reflection)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
{
serializeContext->Class<MathOperatorContract, Contract>()
->Version(1)
->Field("OperatorType", &MathOperatorContract::m_supportedOperator)
->Field("NativeTypes", &MathOperatorContract::m_supportedNativeTypes)
;
}
}
}
@@ -0,0 +1,52 @@
/*
* 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
#include <ScriptCanvas/Core/Contract.h>
#include <ScriptCanvas/Data/Data.h>
namespace ScriptCanvas
{
class MathOperatorContract
: public Contract
{
public:
AZ_CLASS_ALLOCATOR(MathOperatorContract, AZ::SystemAllocator, 0);
AZ_RTTI(MathOperatorContract, "{17B1AEA6-B36B-4EE5-83E9-4563CAC79889}", Contract);
MathOperatorContract() = default;
MathOperatorContract(AZStd::string_view operatorMethod)
: m_supportedOperator(operatorMethod)
{
}
~MathOperatorContract() override = default;
void SetSupportedNativeTypes(const AZStd::unordered_set< Data::Type >& nativeTypes);
void SetSupportedOperator(AZStd::string_view operatorString);
// Was a versioning mishap with the data in this contract that caused the supported
// types and operator to not be serialized. Using this to catch that case and update.
// Function will be removed in a future update.
bool HasOperatorFunction() const;
static void Reflect(AZ::ReflectContext* reflection);
protected:
AZStd::string m_supportedOperator;
AZStd::unordered_set< Data::Type > m_supportedNativeTypes;
AZ::Outcome<void, AZStd::string> OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const override;
AZ::Outcome<void, AZStd::string> OnEvaluateForType(const Data::Type& dataType) const override;
};
}
@@ -0,0 +1,67 @@
/*
* 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 "SlotTypeContract.h"
#include <ScriptCanvas/Core/ContractBus.h>
#include <ScriptCanvas/Core/Slot.h>
namespace ScriptCanvas
{
static const char* GetConnectionFailureReason(const SlotDescriptor& sourceDescriptor, const SlotDescriptor& targetDescriptor)
{
if (sourceDescriptor.m_slotType != targetDescriptor.m_slotType)
{
return "Cannot connect Execution slots to Data slots.";
}
else if (sourceDescriptor.m_connectionType == targetDescriptor.m_connectionType)
{
if (sourceDescriptor.IsInput())
{
return "Cannot connect Input slots to other Input slots";
}
else if (sourceDescriptor.IsOutput())
{
return "Cannot connect Output slots to other Output slots";
}
}
AZ_Assert(false, "Unknown reason for Connection Failure");
return "Unknown reason for Connection Failure";
}
AZ::Outcome<void, AZStd::string> SlotTypeContract::OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const
{
const auto sourceDescriptor = sourceSlot.GetDescriptor();
const auto targetDescriptor = targetSlot.GetDescriptor();
if (sourceDescriptor.CanConnectTo(targetDescriptor))
{
return AZ::Success();
}
return AZ::Failure(AZStd::string::format
( "(%s) - %s "
, RTTI_GetTypeName()
, GetConnectionFailureReason(sourceDescriptor, targetDescriptor)
));
}
void SlotTypeContract::Reflect(AZ::ReflectContext* reflection)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
{
serializeContext->Class<SlotTypeContract, Contract>()
->Version(0)
;
}
}
}
@@ -0,0 +1,35 @@
/*
* 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
#include <ScriptCanvas/Core/Contract.h>
namespace ScriptCanvas
{
class SlotTypeContract
: public Contract
{
public:
AZ_CLASS_ALLOCATOR(SlotTypeContract, AZ::SystemAllocator, 0);
AZ_RTTI(SlotTypeContract, "{084B4F2A-AB34-4931-9269-E3614FC1CDFA}", Contract);
SlotTypeContract() = default;
~SlotTypeContract() override = default;
static void Reflect(AZ::ReflectContext* reflection);
protected:
AZ::Outcome<void, AZStd::string> OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const override;
};
}
@@ -0,0 +1,52 @@
/*
* 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 "precompiled.h"
#include "StorageRequiredContract.h"
#include <ScriptCanvas/Core/ContractBus.h>
#include <ScriptCanvas/Core/NodeBus.h>
#include <ScriptCanvas/Core/Slot.h>
namespace ScriptCanvas
{
AZ::Outcome<void, AZStd::string> StorageRequiredContract::OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const
{
if (sourceSlot.GetType() == SlotType::DataOut && targetSlot.GetType() == SlotType::DataIn)
{
bool isSlotValidStorage{};
NodeRequestBus::EventResult(isSlotValidStorage, targetSlot.GetNodeId(), &NodeRequests::IsSlotValidStorage, targetSlot.GetId());
if (isSlotValidStorage)
{
return AZ::Success();
}
}
AZStd::string errorMessage = AZStd::string::format("Connection cannot be created between source slot \"%s\" and target slot \"%s\", Storage requirement is not met. (%s)"
, sourceSlot.GetName().data()
, targetSlot.GetName().data()
, RTTI_GetTypeName()
);
return AZ::Failure(errorMessage);
}
void StorageRequiredContract::Reflect(AZ::ReflectContext* reflection)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection);
if (serializeContext)
{
serializeContext->Class<StorageRequiredContract, Contract>()
->Version(0)
;
}
}
}
@@ -0,0 +1,34 @@
/*
* 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
#include <ScriptCanvas/Core/Contract.h>
namespace ScriptCanvas
{
class StorageRequiredContract
: public Contract
{
public:
AZ_CLASS_ALLOCATOR(StorageRequiredContract, AZ::SystemAllocator, 0);
AZ_RTTI(StorageRequiredContract, "{AECE109D-121F-477C-995F-D044CA05F88D}", Contract);
StorageRequiredContract() = default;
~StorageRequiredContract() override = default;
static void Reflect(AZ::ReflectContext* reflection);
protected:
AZ::Outcome<void, AZStd::string> OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const override;
};
}
@@ -0,0 +1,81 @@
/*
* 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 "SupportsMethodContract.h"
#include <ScriptCanvas/Core/ContractBus.h>
#include <ScriptCanvas/Core/GraphBus.h>
#include <ScriptCanvas/Core/NodeBus.h>
#include <ScriptCanvas/Core/Endpoint.h>
#include <ScriptCanvas/Core/Slot.h>
#include <ScriptCanvas/Core/Node.h>
namespace ScriptCanvas
{
AZ::Outcome<void, AZStd::string> SupportsMethodContract::OnEvaluate([[maybe_unused]] const Slot& sourceSlot, const Slot& targetSlot) const
{
if (targetSlot.IsDynamicSlot() && targetSlot.HasDisplayType())
{
Data::Type dataType = targetSlot.GetDataType();
return EvaluateForType(dataType);
}
// If the target slot is dynamic. We can assume they are a type match from the regular type matching system.
// So we can just return success and let the dynamic typing system handle ensuring this contract is successfully
// fulfiled.
return AZ::Success();
}
AZ::Outcome<void, AZStd::string> SupportsMethodContract::OnEvaluateForType(const Data::Type& dataType) const
{
AZ::BehaviorContext* behaviorContext(nullptr);
AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationRequests::GetBehaviorContext);
if (!behaviorContext)
{
AZ_Assert(false, "A behavior context is required!");
return AZ::Failure(AZStd::string::format("No Behavior Context"));
}
const AZ::TypeId azDataType = ToAZType(dataType);
const auto classIter(behaviorContext->m_typeToClassMap.find(azDataType));
if (classIter != behaviorContext->m_typeToClassMap.end())
{
AZ::BehaviorClass* behaviorClass = classIter->second;
if (behaviorClass)
{
if (behaviorClass->m_methods.find(m_methodName) != behaviorClass->m_methods.end())
{
return AZ::Success();
}
else
{
return AZ::Failure(AZStd::string::format("Behavior Context does not contain reflection for method %s on class %s", m_methodName.c_str(), azDataType.ToString<AZStd::string>().c_str()));
}
}
}
return AZ::Failure(AZStd::string::format("Behavior Context does not contain reflection for type provided: %s", azDataType.ToString<AZStd::string>().c_str()));
}
void SupportsMethodContract::Reflect(AZ::ReflectContext* reflection)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection);
if (serializeContext)
{
serializeContext->Class<SupportsMethodContract, Contract>()
->Version(0)
->Field("m_methodName", &SupportsMethodContract::m_methodName)
;
}
}
}
@@ -0,0 +1,44 @@
/*
* 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
#include <ScriptCanvas/Core/Contract.h>
namespace ScriptCanvas
{
//! Contracts that verifies if the specified BehaviorContext method name is supported by a data type.
//! This can be used to only allow slot connections if the underlying type is able to call the specified method.
//! For example, container types may support the "Insert" method, while most native or BC types would not.
class SupportsMethodContract
: public Contract
{
public:
AZ_CLASS_ALLOCATOR(SupportsMethodContract, AZ::SystemAllocator, 0);
AZ_RTTI(SupportsMethodContract, "{9C7BD7CB-D11C-4683-8691-F2593D1C294A}", Contract);
SupportsMethodContract() = default;
SupportsMethodContract(const char* methodName)
: m_methodName(methodName)
{}
~SupportsMethodContract() override = default;
static void Reflect(AZ::ReflectContext* reflection);
protected:
AZStd::string m_methodName;
AZ::Outcome<void, AZStd::string> OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const override;
AZ::Outcome<void, AZStd::string> OnEvaluateForType(const Data::Type& dataType) const override;
};
}
@@ -0,0 +1,139 @@
/*
* 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 "TypeContract.h"
#include <ScriptCanvas/Core/ContractBus.h>
#include <ScriptCanvas/Core/NodeBus.h>
#include <ScriptCanvas/Core/Slot.h>
namespace ScriptCanvas
{
void RestrictedTypeContract::Reflect(AZ::ReflectContext* reflection)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection);
if (serializeContext)
{
serializeContext->Class<RestrictedTypeContract, Contract>()
->Version(1)
->Field("flags", &RestrictedTypeContract::m_flags)
->Field("types", &RestrictedTypeContract::m_types)
;
}
}
AZ::Outcome<void, AZStd::string> RestrictedTypeContract::OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const
{
bool valid = false;
if (m_types.empty())
{
valid = m_flags != Exclusive;
}
else
{
if (m_flags == Inclusive)
{
for (const auto& type : m_types)
{
if (targetSlot.IsTypeMatchFor(type))
{
valid = true;
break;
}
}
}
else
{
valid = true;
for (const auto& type : m_types)
{
if (targetSlot.IsTypeMatchFor(type))
{
if (!targetSlot.IsDynamicSlot())
{
valid = false;
break;
}
else if (targetSlot.HasDisplayType())
{
valid = false;
break;
}
}
}
}
}
if (valid)
{
return AZ::Success();
}
AZStd::string errorMessage = AZStd::string::format("Connection cannot be created between source slot \"%s\" and target slot \"%s\" as the types do not satisfy the type requirement. (%s)\n\rValid types are:\n\r"
, sourceSlot.GetName().data()
, targetSlot.GetName().data()
, RTTI_GetTypeName());
for (const auto& type : m_types)
{
if (Data::IsValueType(type))
{
errorMessage.append(AZStd::string::format("%s\n", Data::GetName(type).data()));
}
else
{
errorMessage.append(Data::GetBehaviorClassName(type.GetAZType()));
}
}
return AZ::Failure(errorMessage);
}
AZ::Outcome<void, AZStd::string> RestrictedTypeContract::OnEvaluateForType(const Data::Type& dataType) const
{
bool valid = false;
if (m_flags == Inclusive)
{
valid = m_types.empty();
for (const auto& type : m_types)
{
if (dataType.IS_A(type))
{
valid = true;
break;
}
}
}
else
{
valid = true;
for (const auto& type : m_types)
{
if (dataType.IS_A(type))
{
valid = false;
break;
}
}
}
if (valid)
{
return AZ::Success();
}
AZStd::string errorMessage = AZStd::string::format("The supplied type(%s) does not satisfy the Type Requirement.", Data::GetName(dataType).data());
return AZ::Failure(errorMessage);
}
}
@@ -0,0 +1,67 @@
/*
* 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
#include <AzCore/std/containers/vector.h>
#include <ScriptCanvas/Core/Contract.h>
#include <ScriptCanvas/Data/Data.h>
namespace ScriptCanvas
{
class RestrictedTypeContract
: public Contract
{
public:
AZ_CLASS_ALLOCATOR(RestrictedTypeContract, AZ::SystemAllocator, 0);
AZ_RTTI(RestrictedTypeContract, "{92343025-F306-4457-B646-1E0989521D2C}", Contract);
static void Reflect(AZ::ReflectContext* reflection);
enum Flags : int
{
Inclusive, //> Contract will be satisfied by any of the type Uuids stored in the contract.
Exclusive, //> Contract may satisfy any endpoint except to those types in the contract.
};
RestrictedTypeContract(Flags flags = Inclusive)
: m_flags(flags)
{
}
RestrictedTypeContract(std::initializer_list<Data::Type> types, Flags flags = Inclusive)
: RestrictedTypeContract(types.begin(), types.end(), flags)
{}
template<typename Container>
RestrictedTypeContract(const Container& types, Flags flags = Inclusive)
: RestrictedTypeContract(types.begin(), types.end(), flags)
{}
template<typename InputIterator>
RestrictedTypeContract(InputIterator first, InputIterator last, Flags flags = Inclusive)
: m_types(first, last)
, m_flags(flags)
{}
~RestrictedTypeContract() override = default;
void AddType(Data::Type&& type) { m_types.emplace_back(AZStd::move(type)); }
protected:
Flags m_flags;
AZStd::vector<Data::Type> m_types;
AZ::Outcome<void, AZStd::string> OnEvaluate(const Slot& sourceSlot, const Slot& targetSlot) const override;
AZ::Outcome<void, AZStd::string> OnEvaluateForType(const Data::Type& dataType) const override;
};
}
@@ -0,0 +1,67 @@
/*
* 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 "Core.h"
#include "Attributes.h"
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/RTTI/AttributeReader.h>
namespace ScriptCanvas
{
static bool SlotIdVersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
{
//! Version 1: Slot Ids contained a Crc32 hash of the name given
//! Version 2+: Slot Ids now contain a random Uuid
//! The converter below reads in the old GraphCanvas node <-> ScriptCanvas node map and then iterates over all the
//! GraphCanvas nodes adding a reference to the ScriptCanvas node in it's user data field
if (classElement.GetVersion() <= 1)
{
if (!classElement.RemoveElementByName(AZ_CRC("m_id", 0x7108ece0)))
{
return false;
}
if (classElement.RemoveElementByName(AZ_CRC("m_name", 0xc08c4427)))
{
return false;
}
classElement.AddElementWithData(context, "m_id", AZ::Uuid::CreateRandom());
}
return true;
}
void SlotId::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<SlotId>()
->Version(2, &SlotIdVersionConverter)
->Field("m_id", &SlotId::m_id)
;
}
if (auto* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->Class<SlotId>("SlotId")
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All);
}
}
}
@@ -0,0 +1,133 @@
/*
* 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
#include <AzCore/Component/EntityId.h>
#include <AzCore/Math/MathUtils.h>
#include <AzCore/Memory/Memory.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/hash.h>
#include <AzCore/Component/EntityUtils.h>
#include <AzCore/Component/NamedEntityId.h>
#include <Core/NamedId.h>
// #define EXPRESSION_TEMPLATES_ENABLED
namespace AZ
{
class Entity;
class ReflectContext;
}
namespace ScriptCanvas
{
// A place holder identifier for the AZ::Entity that owns the graph.
// The actual value in each location initialized to GraphOwnerId is populated with the owning entity at editor-time, Asset Processor-time, or runtime, as soon as the owning entity is known.
using GraphOwnerIdType = AZ::EntityId;
static const GraphOwnerIdType GraphOwnerId = AZ::EntityId(0xacedc0de);
// A place holder identifier for unique runtime graph on Entity that is running more than one instance of the same graph.
// This allows multiple instances of the same graph to be addressed individually on the same entity.
// The actual value in each location initialized to UniqueId is populated at run-time.
using RuntimeIdType = AZ::EntityId;
static const RuntimeIdType UniqueId = AZ::EntityId(0xfee1baad);
class Node;
class Edge;
using ID = AZ::EntityId;
using NodeIdList = AZStd::vector<ID>;
using NodePtrList = AZStd::vector<Node*>;
using NodePtrConstList = AZStd::vector<const Node*>;
enum class ExecutionMode : AZ::u8
{
GraphTraversal,
Interpreted,
Native,
};
struct SlotId
{
AZ_TYPE_INFO(SlotId, "{14C629F6-467B-46FE-8B63-48FDFCA42175}");
AZ::Uuid m_id{ AZ::Uuid::CreateNull() };
SlotId() = default;
SlotId(const SlotId&) = default;
explicit SlotId(const AZ::Uuid& uniqueId)
: m_id(uniqueId)
{}
//! AZ::Uuid has a constructor not marked as explicit that accepts a const char*
//! Adding a constructor which accepts a const char* and deleting it prevents
//! AZ::Uuid from being initialized with c-strings
explicit SlotId(const char* str) = delete;
static void Reflect(AZ::ReflectContext* context);
bool IsValid() const
{
return m_id != AZ::Uuid::CreateNull();
}
AZStd::string ToString() const
{
return m_id.ToString<AZStd::string>();
}
bool operator==(const SlotId& rhs) const
{
return m_id == rhs.m_id;
}
bool operator!=(const SlotId& rhs) const
{
return m_id != rhs.m_id;
}
};
using NamedActiveEntityId = AZ::NamedEntityId;
using NamedNodeId = NamedId<AZ::EntityId>;
using NamedSlotId = NamedId<SlotId>;
using NodeTypeIdentifier = AZStd::size_t;
using EBusEventId = AZ::Crc32;
using EBusBusId = AZ::Crc32;
using ScriptCanvasId = AZ::EntityId;
}
namespace AZStd
{
template<>
struct hash<ScriptCanvas::SlotId>
{
using argument_type = ScriptCanvas::SlotId;
using result_type = AZStd::size_t;
AZ_FORCE_INLINE size_t operator()(const argument_type& ref) const
{
return AZStd::hash<AZ::Uuid>()(ref.m_id);
}
};
}
#define SCRIPT_CANVAS_INFINITE_LOOP_DETECTION_COUNT (2000000)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,554 @@
/*
* 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
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/std/any.h>
#include <AzCore/std/string/string_view.h>
#include <ScriptCanvas/Data/Data.h>
#include <ScriptCanvas/Data/DataTrait.h>
#include <ScriptCanvas/Data/BehaviorContextObject.h>
#include <AzCore/Outcome/Outcome.h>
namespace AZ
{
class ReflectContext;
}
namespace ScriptCanvas
{
struct BehaviorContextResultTag { explicit BehaviorContextResultTag() = default; };
const BehaviorContextResultTag s_behaviorContextResultTag{};
using ComparisonOutcome = AZ::Outcome<bool, AZStd::string>;
/// A Datum is used to provide generic storage for all data types in ScriptCanvas, and provide a common interface to accessing, modifying, and displaying them
/// in the editor, regardless of their actual ScriptCanvas or BehaviorContext type.
class Datum final
{
public:
/// \todo support polymorphism
AZ_TYPE_INFO(Datum, "{8B836FC0-98A8-4A81-8651-35C7CA125451}");
AZ_CLASS_ALLOCATOR(Datum, AZ::SystemAllocator, 0);
enum class eOriginality : int
{
Original,
Copy
};
// calls a function and converts the result to a ScriptCanvas type, if necessary
static AZ::Outcome<Datum, AZStd::string> CallBehaviorContextMethodResult(const AZ::BehaviorMethod* method, const AZ::BehaviorParameter* resultType, AZ::BehaviorValueParameter* params, unsigned int numExpectedArgs);
static AZ::Outcome<void, AZStd::string> CallBehaviorContextMethod(const AZ::BehaviorMethod* method, AZ::BehaviorValueParameter* params, unsigned int numExpectedArgs);
static bool IsValidDatum(const Datum* datum);
static void Reflect(AZ::ReflectContext* reflectContext);
Datum();
Datum(const Datum& object);
Datum(Datum&& object);
Datum(const Data::Type& type, eOriginality originality);
Datum(const Data::Type& type, eOriginality originality, const void* source, const AZ::Uuid& sourceTypeID);
Datum(const AZ::BehaviorParameter& parameterDesc, eOriginality originality, const void* source);
Datum(BehaviorContextResultTag, const AZ::BehaviorParameter& resultType);
Datum(const AZStd::string& behaviorClassName, eOriginality originality);
Datum(const AZ::BehaviorValueParameter& value);
void ReconfigureDatumTo(Datum&& object);
void ReconfigureDatumTo(const Datum& object);
void DeepCopyDatum(const Datum& object);
const AZStd::any& ToAny() const
{
return m_storage;
}
/// If t_Value is a ScriptCanvas value type, regardless of pointer/reference, this will create datum with a copy of that
/// value. That is, Datum<AZ::Vector3>(source), Datum<AZ::Vector3&>(source), Datum<AZ::Vector3*>(&source), will all produce
/// a copy of source. If t_Value is a ScriptCanvas reference type, passing in a pointer or reference will created a datum
/// that REFERS to the source, and passing in a value will create a datum with a new, Script-owned, copy from the source.
//
// Also needs to bypass when it conflicts with the other constructors available.
template<typename t_Value, typename = AZStd::enable_if_t<!AZStd::is_same<AZStd::decay_t<t_Value>, Datum>::value && !AZStd::is_same<AZStd::decay_t<t_Value>, AZ::BehaviorValueParameter>::value> >
explicit Datum(t_Value&& value);
AZ_INLINE bool Empty() const;
//! use RARELY, this is dangerous. Use ONLY to read the value contained by this Datum, never to modify
template<typename t_Value>
const t_Value* GetAs() const;
/// \note Directly modifying the data circumvents all of the runtime (and even the edit time) handling of script canvas data.
/// This is dangerous in that one may not be properly handling values, like converting numeric types to the supported numeric type,
/// or modifying objects without notifying systems whose correctness depends on changes in those values.
/// Use with extreme caution. This will made clearer and easier in a future API change.
AZ_INLINE const void* GetAsDanger() const;
const Data::Type& GetType() const { return m_type; }
void SetType(const Data::Type& dataType);
template<typename T>
void SetAZType()
{
SetType(ScriptCanvas::Data::FromAZType(azrtti_typeid<T>()));
}
// checks this datum can be converted to the specified type, including checking for required storage
AZ_INLINE bool IsConvertibleFrom(const AZ::Uuid& typeID) const;
AZ_INLINE bool IsConvertibleFrom(const Data::Type& type) const;
// checks if the type of this datum can be converted to the specified type, regardless of storage
AZ_INLINE bool IsConvertibleTo(const AZ::Uuid& typeID) const;
AZ_INLINE bool IsConvertibleTo(const Data::Type& type) const;
bool IsConvertibleTo(const AZ::BehaviorParameter& parameterDesc) const;
bool IsDefaultValue() const;
// todo support polymorphism
// returns true if this type IS_A t_Value type
template<typename t_Value>
bool IS_A() const;
// todo support polymorphism
AZ_INLINE bool IS_A(const Data::Type& type) const;
//! use RARELY, this is dangerous as it circumvents ScriptCanvas execution. Use to initialize values more simply in unit testing, or assist debugging.
template<typename t_Value>
t_Value* ModAs();
AZ_INLINE void* ModAsDanger();
// can cause de-allocation of original datum, to which other data can point!
Datum& operator=(const Datum& other);
Datum& operator=(Datum&& other);
ComparisonOutcome operator==(const Datum& other) const;
ComparisonOutcome operator!=(const Datum& other) const;
ComparisonOutcome operator<(const Datum& other) const;
ComparisonOutcome operator<=(const Datum& other) const;
ComparisonOutcome operator>(const Datum& other) const;
ComparisonOutcome operator>=(const Datum& other) const;
// use RARELY, this is dangerous
template<typename t_Value>
AZ_INLINE bool Set(const t_Value& value);
void SetToDefaultValueOfType();
void SetNotificationsTarget(AZ::EntityId notificationId);
// pushes this datum to the void* address in destination
bool ToBehaviorContext(AZ::BehaviorValueParameter& destination) const;
// creates an AZ::BehaviorValueParameter with a void* that points to this datum, depending on what the parameter needs
// this is called when the AZ::BehaviorValueParameter needs this value as input to another function
// so it is appropriate for the value output to be nullptr
AZ::Outcome<AZ::BehaviorValueParameter, AZStd::string> ToBehaviorValueParameter(const AZ::BehaviorParameter& description) const;
AZ_INLINE AZStd::string ToString() const;
bool ToString(Data::StringType& result) const;
void SetLabel(AZStd::string_view name);
AZStd::string GetLabel() const;
void SetVisibility(AZ::Crc32 visibility);
AZ::Crc32 GetVisibility() const;
// Remaps references to the SelfReference Entity Id to the Entity Id of the ScriptCanvas Graph component owner
// This should be called at ScriptCanvas compile time when the runtime entity is available
void ResolveSelfEntityReferences(const AZ::EntityId& graphOwnerId);
// creates an AZ::BehaviorValueParameter with a void* that points to this datum, depending on what the parameter needs
// this is called when the AZ::BehaviorValueParameter needs this value as output from another function
// so it is NOT appropriate for the value output to be nullptr, if the description is for a pointer to an object
// there needs to be valid memory to write that pointer
AZ::Outcome<AZ::BehaviorValueParameter, AZStd::string> ToBehaviorValueParameterResult(const AZ::BehaviorParameter& description);
// This is used as the destination for a Behavior Context function call; after the call the result must be converted.
void ConvertBehaviorContextMethodResult(const AZ::BehaviorParameter& resultType);
private:
AZ::Crc32 GetDatumVisibility() const;
template<typename t_Value, bool isReference>
struct InitializerHelper
{
static void Help(const t_Value& value, Datum& datum)
{
const bool isValue = Data::Traits<t_Value>::s_isNative || !isReference;
datum.Initialize(Data::FromAZType(Data::Traits<t_Value>::GetAZType()), isValue ? Datum::eOriginality::Original : Datum::eOriginality::Copy, reinterpret_cast<const void*>(&value), azrtti_typeid<t_Value>());
}
};
template<typename t_Value, bool isReference>
struct InitializerHelper<t_Value*, isReference>
{
static void Help(const t_Value* value, Datum& datum)
{
datum.Initialize(Data::FromAZType(Data::Traits<t_Value>::GetAZType()), Datum::eOriginality::Copy, reinterpret_cast<const void*>(value), azrtti_typeid<t_Value>());
}
};
template<typename t_Value>
struct GetAsHelper
{
static const t_Value* Help(Datum& datum)
{
static_assert(!AZStd::is_pointer<t_Value>::value, "no pointer types in the Datum::GetAsHelper<t_Value, false>");
if (datum.m_type.GetType() == Data::eType::BehaviorContextObject)
{
return (*AZStd::any_cast<BehaviorContextObjectPtr>(&datum.m_storage))->CastConst<t_Value>();
}
else
{
return AZStd::any_cast<const t_Value>(&datum.m_storage);
}
}
};
template<typename t_Value>
struct GetAsHelper<t_Value*>
{
static const t_Value** Help(Datum& datum)
{
datum.m_pointer = const_cast<void*>(static_cast<const void*>(GetAsHelper<AZStd::decay_t<t_Value>>::Help(datum)));
return (const t_Value**)(&datum.m_pointer);
}
};
class SerializeContextEventHandler : public AZ::SerializeContext::IEventHandler
{
public:
/// Called after we are done writing to the instance pointed by classPtr.
void OnWriteEnd(void* classPtr) override
{
Datum* datum = reinterpret_cast<Datum*>(classPtr);
datum->OnWriteEnd();
}
};
friend class SerializeContextEventHandler;
static ComparisonOutcome CallComparisonOperator(AZ::Script::Attributes::OperatorType operatorType, const AZ::BehaviorClass& behaviorClass, const Datum& lhs, const Datum& rhs);
// is this storage for nodes that are overloaded, e.g. Log, which takes in any data type
const bool m_isOverloadedStorage = false;
bool m_isDefaultConstructed = false;
// eOriginality records the graph source of the object
eOriginality m_originality = eOriginality::Copy;
// storage for the datum, regardless of ScriptCanvas::Data::Type
AZStd::any m_storage;
// This contains the editor label for m_storage.
AZStd::string m_datumLabel;
// This contains the editor visibility for m_storage.
AZ::Crc32 m_visibility{ AZ::Edit::PropertyVisibility::ShowChildrenOnly };
// storage for implicit conversions, when needed
AZStd::any m_conversionStorage;
// the least derived class this datum can accept
const AZ::BehaviorClass* m_class = nullptr;
// storage for pointer, if necessary
mutable void* m_pointer = nullptr;
// the ScriptCanvas type of the object
Data::Type m_type;
// The notificationId to send change notifications to.
AZ::EntityId m_notificationId;
// Destroys the datum, and the type information
void Clear();
bool FromBehaviorContext(const void* source);
bool FromBehaviorContext(const void* source, const AZ::Uuid& typeID);
bool FromBehaviorContextNumber(const void* source, const AZ::Uuid& typeID);
bool FromBehaviorContextObject(const AZ::BehaviorClass* behaviorClass, const void* source);
const void* GetValueAddress() const;
bool Initialize(const Data::Type& type, eOriginality originality, const void* source, const AZ::Uuid& sourceTypeID);
bool InitializeBehaviorContextParameter(const AZ::BehaviorParameter& parameterDesc, eOriginality originality, const void* source);
bool InitializeAABB(const void* source);
bool InitializeAssetId(const void* source);
bool InitializeBehaviorContextObject(eOriginality originality, const void* source);
bool InitializeBehaviorContextMethodResult(const AZ::BehaviorParameter& resultType);
bool InitializeBool(const void* source);
bool InitializeColor(const void* source);
bool InitializeCRC(const void* source);
bool InitializeEntityID(const void* source);
bool InitializeNamedEntityID(const void* source);
bool InitializeMatrix3x3(const void* source);
bool InitializeMatrix4x4(const void* source);
bool InitializeNumber(const void* source, const AZ::Uuid& sourceTypeID);
bool InitializeOBB(const void* source);
bool InitializePlane(const void* source);
bool InitializeQuaternion(const void* source);
bool InitializeString(const void* source, const AZ::Uuid& sourceTypeID);
bool InitializeTransform(const void* source);
AZ_INLINE bool InitializeOverloadedStorage(const Data::Type& type, eOriginality originality);
bool InitializeVector2(const void* source, const AZ::Uuid& sourceTypeID);
bool InitializeVector3(const void* source, const AZ::Uuid& sourceTypeID);
bool InitializeVector4(const void* source, const AZ::Uuid& sourceTypeID);
void* ModResultAddress();
void* ModValueAddress() const;
void OnDatumEdited();
void OnReadBegin();
void OnWriteEnd();
AZ_INLINE bool SatisfiesTraits(AZ::u8 behaviorValueTraits) const;
bool ToBehaviorContextNumber(void* target, const AZ::Uuid& typeID) const;
AZ::BehaviorValueParameter ToBehaviorValueParameterNumber(const AZ::BehaviorParameter& description);
AZ::Outcome<AZ::BehaviorValueParameter, AZStd::string> ToBehaviorValueParameterString(const AZ::BehaviorParameter& description);
AZStd::string ToStringAABB(const Data::AABBType& source) const;
AZStd::string ToStringColor(const Data::ColorType& source) const;
AZStd::string ToStringCRC(const Data::CRCType& source) const;
bool ToStringBehaviorClassObject(Data::StringType& result) const;
AZStd::string ToStringMatrix3x3(const AZ::Matrix3x3& source) const;
AZStd::string ToStringMatrix4x4(const AZ::Matrix4x4& source) const;
AZStd::string ToStringOBB(const Data::OBBType& source) const;
AZStd::string ToStringPlane(const Data::PlaneType& source) const;
AZStd::string ToStringQuaternion(const Data::QuaternionType& source) const;
AZStd::string ToStringTransform(const Data::TransformType& source) const;
AZStd::string ToStringVector2(const AZ::Vector2& source) const;
AZStd::string ToStringVector3(const AZ::Vector3& source) const;
AZStd::string ToStringVector4(const AZ::Vector4& source) const;
}; // class Datum
template<typename t_Value, typename>
Datum::Datum(t_Value&& value)
{
InitializerHelper<AZStd::remove_reference_t<t_Value>, AZStd::is_reference<t_Value>::value>::Help(value, *this);
}
bool Datum::Empty() const
{
return GetValueAddress() == nullptr;
}
template<typename t_Value>
const t_Value* Datum::GetAs() const
{
return GetAsHelper<t_Value>::Help(*const_cast<Datum*>(this));
}
#define DATUM_GET_NUMBER_SPECIALIZE(NUMERIC_TYPE)\
template<>\
struct Datum::GetAsHelper<NUMERIC_TYPE>\
{\
AZ_FORCE_INLINE static const NUMERIC_TYPE* Help(Datum& datum)\
{\
static_assert(!AZStd::is_pointer<NUMERIC_TYPE>::value, "no pointer types in the Datum::GetAsHelper<" #NUMERIC_TYPE ">");\
void* numberStorage(const_cast<void*>(reinterpret_cast<const void*>(&datum.m_conversionStorage)));\
return datum.IS_A(Data::Type::Number()) && datum.ToBehaviorContextNumber(numberStorage, AZ::AzTypeInfo<NUMERIC_TYPE>::Uuid())\
? reinterpret_cast<const NUMERIC_TYPE*>(numberStorage)\
: nullptr;\
}\
};
DATUM_GET_NUMBER_SPECIALIZE(char);
DATUM_GET_NUMBER_SPECIALIZE(short);
DATUM_GET_NUMBER_SPECIALIZE(int);
DATUM_GET_NUMBER_SPECIALIZE(long);
DATUM_GET_NUMBER_SPECIALIZE(AZ::s8);
DATUM_GET_NUMBER_SPECIALIZE(AZ::s64);
DATUM_GET_NUMBER_SPECIALIZE(unsigned char);
DATUM_GET_NUMBER_SPECIALIZE(unsigned int);
DATUM_GET_NUMBER_SPECIALIZE(unsigned long);
DATUM_GET_NUMBER_SPECIALIZE(unsigned short);
DATUM_GET_NUMBER_SPECIALIZE(AZ::u64);
DATUM_GET_NUMBER_SPECIALIZE(float);
// only requred if the ScriptCanvas::NumberType changes from double, see set specialization below
//DATUM_GET_NUMBER_SPECIALIZE(double);
const void* Datum::GetAsDanger() const
{
return GetValueAddress();
}
template<typename t_Value>
bool Datum::IS_A() const
{
static_assert(!AZStd::is_pointer<t_Value>::value, "no pointer types in the Datum::Is, please");
return m_type.IS_A(Data::FromAZType(azrtti_typeid<t_Value>()));
}
bool Datum::IS_A(const Data::Type& type) const
{
return Data::IS_A(m_type, type);
}
bool Datum::IsConvertibleFrom(const AZ::Uuid& typeID) const
{
return m_type.IsConvertibleFrom(typeID);
}
bool Datum::IsConvertibleFrom(const Data::Type& type) const
{
return m_type.IsConvertibleTo(type);
}
bool Datum::IsConvertibleTo(const AZ::Uuid& typeID) const
{
return m_type.IsConvertibleTo(typeID);
}
bool Datum::IsConvertibleTo(const Data::Type& type) const
{
return m_type.IsConvertibleTo(type);
}
bool Datum::InitializeOverloadedStorage(const Data::Type& type, eOriginality originality)
{
return m_isOverloadedStorage && type.IsValid() && (m_type.IS_EXACTLY_A(type) || Initialize(type, originality, nullptr, AZ::Uuid::CreateNull()));
}
template<typename t_Value>
t_Value* Datum::ModAs()
{
return const_cast<t_Value*>(GetAs<t_Value>());
}
void* Datum::ModAsDanger()
{
return ModValueAddress();
}
bool Datum::SatisfiesTraits(AZ::u8 behaviorValueTraits) const
{
AZ_Assert(!(behaviorValueTraits & AZ::BehaviorParameter::TR_POINTER && behaviorValueTraits & AZ::BehaviorParameter::TR_REFERENCE), "invalid traits on behavior parameter");
return GetValueAddress() || (!(behaviorValueTraits & AZ::BehaviorParameter::TR_THIS_PTR) && (behaviorValueTraits & AZ::BehaviorParameter::TR_POINTER));
}
template<typename t_Value>
bool Datum::Set(const t_Value& value)
{
static_assert(!AZStd::is_pointer<t_Value>::value, "no pointer types in the Datum::Set, please");
InitializeOverloadedStorage(Data::FromAZType(azrtti_typeid<t_Value>()), eOriginality::Copy);
AZ_Error("Script Canvas", !IS_A(Data::Type::Number()) || azrtti_typeid<t_Value>() == azrtti_typeid<Data::NumberType>(), "Set on number types must be specialized!");
if (IS_A<t_Value>())
{
if (Data::IsValueType(m_type))
{
m_storage = value;
return true;
}
else
{
return FromBehaviorContext(static_cast<const void*>(&value));
}
}
return false;
}
#define DATUM_SET_NUMBER_SPECIALIZE(NUMERIC_TYPE)\
template<>\
AZ_INLINE bool Datum::Set(const NUMERIC_TYPE& value)\
{\
return FromBehaviorContextNumber(&value, azrtti_typeid<NUMERIC_TYPE>());\
}
DATUM_SET_NUMBER_SPECIALIZE(char);
DATUM_SET_NUMBER_SPECIALIZE(short);
DATUM_SET_NUMBER_SPECIALIZE(int);
DATUM_SET_NUMBER_SPECIALIZE(long);
DATUM_SET_NUMBER_SPECIALIZE(AZ::s8);
DATUM_SET_NUMBER_SPECIALIZE(AZ::s64);
DATUM_SET_NUMBER_SPECIALIZE(unsigned char);
DATUM_SET_NUMBER_SPECIALIZE(unsigned int);
DATUM_SET_NUMBER_SPECIALIZE(unsigned long);
DATUM_SET_NUMBER_SPECIALIZE(unsigned short);
DATUM_SET_NUMBER_SPECIALIZE(AZ::u64);
DATUM_SET_NUMBER_SPECIALIZE(float);
// only requried if the ScriptCanvas::NumberType changes from double, see get specialization above
//DATUM_SET_NUMBER_SPECIALIZE(double);
// vectors are the most convertible objects, so more get/set specialization is necessary
#define DATUM_SET_VECTOR_SPECIALIZE(VECTOR_TYPE)\
template<>\
AZ_INLINE bool Datum::Set(const VECTOR_TYPE& value)\
{\
if (FromBehaviorContext(&value, azrtti_typeid<VECTOR_TYPE>()))\
{\
return true;\
}\
return false;\
}
DATUM_SET_VECTOR_SPECIALIZE(AZ::Vector2);
DATUM_SET_VECTOR_SPECIALIZE(AZ::Vector3);
DATUM_SET_VECTOR_SPECIALIZE(AZ::Vector4);
AZStd::string Datum::ToString() const
{
AZStd::string result;
ToString(result);
return result;
}
} // namespace ScriptCanvas
@@ -0,0 +1,45 @@
/*
* 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
#include "Core.h"
#include <AzCore/EBus/EBus.h>
#include <AzCore/Component/EntityId.h>
namespace ScriptCanvas
{
class Datum;
class DatumNotifications : public AZ::EBusTraits
{
public:
using MutexType = AZStd::recursive_mutex;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = AZ::EntityId;
virtual void OnDatumEdited(const Datum* datum) = 0;
};
using DatumNotificationBus = AZ::EBus<DatumNotifications>;
class DatumSystemNotifications : public AZ::EBusTraits
{
public:
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
virtual void OnDatumChanged(Datum&) = 0;
};
using DatumSystemNotificationBus = AZ::EBus<DatumSystemNotifications>;
}
@@ -0,0 +1,31 @@
/*
* 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
#include <AzCore/EBus/EBus.h>
#include <ScriptCanvas/Core/Core.h>
#include <ScriptCanvas/Core/GraphScopedTypes.h>
namespace ScriptCanvas
{
class EBusHandlerNodeRequests : public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = GraphScopedNodeId;
virtual void SetAddressId(const Datum& datumValue) = 0;
};
using EBusHandlerNodeRequestBus = AZ::EBus<EBusHandlerNodeRequests>;
}
@@ -0,0 +1,98 @@
/*
* 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 "Endpoint.h"
#include <AzCore/Serialization/SerializeContext.h>
namespace ScriptCanvas
{
Endpoint::Endpoint(const AZ::EntityId& nodeId, const SlotId& slotId)
: m_nodeId(nodeId)
, m_slotId(slotId)
{}
bool Endpoint::operator==(const Endpoint& other) const
{
return m_nodeId == other.m_nodeId && m_slotId == other.m_slotId;
}
void Endpoint::Reflect(AZ::ReflectContext* reflection)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection);
if (serializeContext)
{
serializeContext->Class<Endpoint>()
->Version(1)
->Field("nodeId", &Endpoint::m_nodeId)
->Field("slotId", &Endpoint::m_slotId)
;
}
}
NamedEndpoint::NamedEndpoint
( const AZ::EntityId& nodeId
, const AZStd::string& nodeName
, const SlotId& slotId
, const AZStd::string& slotName)
: Endpoint(nodeId, slotId)
, m_nodeName(nodeName)
, m_slotName(slotName)
{}
NamedEndpoint::NamedEndpoint(const Endpoint& endpoint)
: Endpoint(endpoint)
{}
const AZStd::string& NamedEndpoint::GetNodeName() const
{
return m_nodeName;
}
NamedNodeId NamedEndpoint::GetNamedNodeId() const
{
return NamedNodeId(m_nodeId, m_nodeName);
}
const AZStd::string& NamedEndpoint::GetSlotName() const
{
return m_slotName;
}
NamedSlotId NamedEndpoint::GetNamedSlotId() const
{
return NamedSlotId(m_slotId, m_nodeName);
}
bool NamedEndpoint::operator==(const Endpoint& other) const
{
return Endpoint::operator==(other);
}
bool NamedEndpoint::operator==(const NamedEndpoint& other) const
{
return Endpoint::operator==(other);
}
void NamedEndpoint::Reflect(AZ::ReflectContext* reflection)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
{
serializeContext->Class<NamedEndpoint, Endpoint>()
->Version(0)
->Field("nodeName", &NamedEndpoint::m_nodeName)
->Field("slotName", &NamedEndpoint::m_slotName)
;
}
}
}
@@ -0,0 +1,104 @@
/*
* 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
#include "Core.h"
namespace ScriptCanvas
{
class Endpoint
{
public:
AZ_CLASS_ALLOCATOR(Endpoint, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(Endpoint, "{91D4ADAC-56FE-4D82-B9AF-6975D21435C8}");
Endpoint() = default;
Endpoint(const AZ::EntityId& nodeId, const SlotId& slotId);
~Endpoint() = default;
bool operator==(const Endpoint& other) const;
static void Reflect(AZ::ReflectContext* reflection);
const AZ::EntityId& GetNodeId() const { return m_nodeId; }
const SlotId& GetSlotId() const { return m_slotId; }
bool IsValid() const { return m_nodeId.IsValid() && m_slotId.IsValid(); }
protected:
AZ::EntityId m_nodeId;
SlotId m_slotId;
};
class NamedEndpoint
: public Endpoint
{
public:
AZ_CLASS_ALLOCATOR(NamedEndpoint, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(NamedEndpoint, "{E4FAB996-1958-4445-8C8B-367F582773F7}");
static void Reflect(AZ::ReflectContext* reflection);
AZStd::string m_nodeName;
AZStd::string m_slotName;
NamedEndpoint() = default;
explicit NamedEndpoint(const Endpoint& endpoint);
NamedEndpoint
( const AZ::EntityId& nodeId
, const AZStd::string& nodeName
, const SlotId& slotId
, const AZStd::string& slotName);
~NamedEndpoint() = default;
const AZStd::string& GetNodeName() const;
NamedNodeId GetNamedNodeId() const;
const AZStd::string& GetSlotName() const;
NamedSlotId GetNamedSlotId() const;
bool operator==(const Endpoint& other) const;
bool operator==(const NamedEndpoint& other) const;
};
}
namespace AZStd
{
template<>
struct hash<ScriptCanvas::Endpoint>
{
using argument_type = ScriptCanvas::Endpoint;
using result_type = AZStd::size_t;
AZ_FORCE_INLINE size_t operator()(const argument_type& ref) const
{
result_type seed = 0;
hash_combine(seed, ref.GetNodeId());
hash_combine(seed, ref.GetSlotId());
return seed;
}
};
template<>
struct hash<ScriptCanvas::NamedEndpoint>
{
using argument_type = ScriptCanvas::NamedEndpoint;
using result_type = AZStd::size_t;
AZ_FORCE_INLINE size_t operator()(const argument_type& ref) const
{
return hash<ScriptCanvas::Endpoint>()(ref);
}
};
}
@@ -0,0 +1,367 @@
/*
* 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 "Core.h"
#include "ExecutionNotificationsBus.h"
namespace ScriptCanvas
{
void ReflectExecutionBusArguments(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
NamedVariabledId::Reflect(context);
NamedNodeId::Reflect(context);
NamedSlotId::Reflect(context);
serializeContext->Class<GraphIdentifier>()
->Version(0)
->Field("uniqueIdentifier", &GraphIdentifier::m_componentId)
->Field("assetId", &GraphIdentifier::m_assetId)
;
serializeContext->Class<ActiveGraphStatus>()
->Version(0)
->Field("IsObserved", &ActiveGraphStatus::m_isObserved)
;
serializeContext->Class<ActiveEntityStatus>()
->Version(0)
->Field("NamedEntityId", &ActiveEntityStatus::m_namedEntityId)
->Field("ActiveGraphs", &ActiveEntityStatus::m_activeGraphs)
;
serializeContext->Class<GraphInfo>()
->Version(0)
->Field("runtimeEntityId", &GraphInfo::m_runtimeEntity)
->Field("graphIdentifier", &GraphInfo::m_graphIdentifier)
;
serializeContext->Class<DatumValue>()
->Version(1)
->Field("behaviorContextObjectType", &DatumValue::m_behaviorContextObjectType)
->Field("value", &DatumValue::m_datum)
;
serializeContext->Class<LoggableEvent>()
->Version(0)
;
serializeContext->Class<Signal, GraphInfo>()
->Version(1)
->Field("endpoint", &Signal::m_endpoint)
->Field("data", &Signal::m_data)
->Field("nodeType", &Signal::m_nodeType)
;
serializeContext->Class<ActivationInfo, GraphInfo>()
->Version(1)
->Field("entityIsObserved", &ActivationInfo::m_entityIsObserved)
->Field("variableValues", &ActivationInfo::m_variableValues)
;
Breakpoint::Reflect(context);
serializeContext->Class<GraphInfoEventBase, GraphInfo, LoggableEvent>()
->Version(0)
->Field("Timestamp", &GraphInfoEventBase::m_timestamp)
;
serializeContext->Class<ExecutionThreadBeginning, GraphInfo, LoggableEvent>()
->Version(0)
->Field("entityNodeId", &ExecutionThreadBeginning::m_nodeId)
->Field("Timestamp", &ExecutionThreadBeginning::m_timestamp)
;
ExecutionThreadEnd::Reflect(context);
GraphActivation::Reflect(context);
GraphDeactivation::Reflect(context);
InputSignal::Reflect(context);
serializeContext->Class<NodeStateChange, GraphInfoEventBase>()
->Version(0)
;
serializeContext->Class<AnnotateNodeSignal, GraphInfoEventBase>()
->Version(0)
->Field("AnnotationLevel", &AnnotateNodeSignal::m_annotationLevel)
->Field("Annotation", &AnnotateNodeSignal::m_annotation)
->Field("AssetNodeId", &AnnotateNodeSignal::m_assetNodeId)
;
serializeContext->Class<OutputDataSignal, GraphInfoEventBase>()
->Version(1)
->Field("Endpoint", &OutputDataSignal::m_endpoint)
->Field("DatumValue", &OutputDataSignal::m_outputValue)
->Field("NodeType", &OutputDataSignal::m_nodeType)
;
OutputSignal::Reflect(context);
VariableChange::Reflect(context);
}
}
ActivationInfo::ActivationInfo(const GraphInfo& info)
: GraphInfo(info)
{}
ActivationInfo::ActivationInfo(const GraphInfo& info, const VariableValues& variableValues)
: GraphInfo(info)
, m_variableValues(variableValues)
{}
AZStd::string ActivationInfo::ToString() const
{
return AZStd::string::format("Entity: %s, Graph: %s, Variables: %s", m_runtimeEntity.ToString().data(), GraphInfo::ToString().data(), ScriptCanvas::ToString(m_variableValues).data());
}
///////////////
// DatumValue
///////////////
DatumValue DatumValue::Create(const GraphVariable& value)
{
if (value.GetDatum()->GetType().GetType() == Data::eType::BehaviorContextObject)
{
return DatumValue(value.GetDatum()->GetType().GetAZType(), AZStd::string::format("(%p) %s", value.GetDatum()->GetAsDanger(), value.GetDatum()->ToString().data()));
}
else
{
return DatumValue((*value.GetDatum()));
}
}
AZStd::string DatumValue::ToString() const
{
if (m_behaviorContextObjectType.IsNull())
{
return Data::GetBehaviorClassName(m_behaviorContextObjectType);
}
else
{
return Data::GetName(m_datum.GetType());
}
}
ExecutionThreadBeginning::ExecutionThreadBeginning()
{}
LoggableEvent* ExecutionThreadBeginning::Duplicate() const
{
return aznew ExecutionThreadBeginning(*this);
}
Timestamp ExecutionThreadBeginning::GetTimestamp() const
{
return m_timestamp;
}
void ExecutionThreadBeginning::SetTimestamp(Timestamp timestamp)
{
m_timestamp = timestamp;
}
void ExecutionThreadBeginning::Visit(LoggableEventVisitor& visitor)
{
visitor.Visit(*this);
}
AZStd::string ExecutionThreadBeginning::ToString() const
{
return AZStd::string::format("ExecutionThreadBeginning: %s, %s", m_nodeId.ToString().data(), GraphInfo::ToString().data());
}
bool GraphIdentifier::operator==(const GraphIdentifier& other) const
{
return m_assetId == other.m_assetId && m_componentId == other.m_componentId;
}
AZStd::string GraphIdentifier::ToString() const
{
return AZStd::string::format("Asset: %s, ComponentId: %llu", m_assetId.ToString<AZStd::string>().data(), m_componentId);
}
bool GraphInfo::operator==(const GraphInfo& other) const
{
return m_runtimeEntity == other.m_runtimeEntity
&& m_graphIdentifier == other.m_graphIdentifier;
}
AZStd::string GraphInfo::ToString() const
{
return AZStd::string::format("Entity: %s, %s", m_runtimeEntity.ToString().data(), m_graphIdentifier.ToString().data());
}
NodeStateChange::NodeStateChange()
{}
LoggableEvent* NodeStateChange::Duplicate() const
{
return aznew NodeStateChange(*this);
}
AZStd::string NodeStateChange::ToString() const
{
// \todo I think....this should get...cut...it's not actually a script canvas level feature
return "NodeStateChange";
}
void NodeStateChange::Visit(LoggableEventVisitor& visitor)
{
visitor.Visit(*this);
}
GraphInfoEventBase::GraphInfoEventBase()
: m_timestamp(AZStd::GetTimeUTCMilliSecond())
{
}
GraphInfoEventBase::GraphInfoEventBase(const GraphInfo& graphInfo)
: GraphInfo(graphInfo)
, m_timestamp(AZStd::GetTimeUTCMilliSecond())
{
}
Timestamp GraphInfoEventBase::GetTimestamp() const
{
return m_timestamp;
}
void GraphInfoEventBase::SetTimestamp(Timestamp timestamp)
{
m_timestamp = timestamp;
}
AnnotateNodeSignal::AnnotateNodeSignal()
: m_annotationLevel(AnnotationLevel::Info)
{
}
AnnotateNodeSignal::AnnotateNodeSignal(const GraphInfo& graphInfo, AnnotationLevel annotationLevel, AZStd::string_view annotation, const AZ::NamedEntityId& assetId)
: GraphInfoEventBase(graphInfo)
, m_annotationLevel(annotationLevel)
, m_annotation(annotation)
, m_assetNodeId(assetId)
{
}
LoggableEvent* AnnotateNodeSignal::Duplicate() const
{
return aznew AnnotateNodeSignal((*this));
}
AZStd::string AnnotateNodeSignal::ToString() const
{
AZStd::string_view annotationLevel;
switch (m_annotationLevel)
{
case AnnotationLevel::Info:
annotationLevel = "Info";
break;
case AnnotationLevel::Warning:
annotationLevel = "Warning";
break;
case AnnotationLevel::Error:
annotationLevel = "Error";
break;
default:
break;
}
return AZStd::string::format("%s - %s - %s", m_assetNodeId.ToString().c_str(), annotationLevel.data(), m_annotation.c_str());
}
void AnnotateNodeSignal::Visit(LoggableEventVisitor& visitor)
{
visitor.Visit(*this);
}
OutputDataSignal::OutputDataSignal(const GraphInfo& graphInfo, const NodeTypeIdentifier& nodeType, const NamedEndpoint& namedEndpoint, const DatumValue& value)
: GraphInfoEventBase(graphInfo)
, m_nodeType(nodeType)
, m_endpoint(namedEndpoint)
, m_outputValue(value)
{
}
LoggableEvent* OutputDataSignal::Duplicate() const
{
return aznew OutputDataSignal((*this));
}
AZStd::string OutputDataSignal::ToString() const
{
return AZStd::string::format("Data (%s) pushed from (%s::%s)", m_outputValue.ToString().c_str(), m_endpoint.GetNodeName().c_str(), m_endpoint.GetSlotName().c_str());
}
void OutputDataSignal::Visit(LoggableEventVisitor& visitor)
{
visitor.Visit((*this));
}
bool Signal::operator==(const Signal& other) const
{
return m_runtimeEntity == other.m_runtimeEntity
&& m_graphIdentifier == other.m_graphIdentifier
&& m_endpoint == other.m_endpoint;
}
AZStd::string Signal::ToString() const
{
return AZStd::string::format("Graph: %s, Node: %s:%s, Slot: %s:%s, Input: %s"
, GraphInfo::ToString().data()
, m_endpoint.GetNodeId().ToString().data()
, m_endpoint.GetNodeName().data()
, m_endpoint.GetSlotId().ToString().data()
, m_endpoint.GetSlotName().data()
, ScriptCanvas::ToString(m_data).data());
}
AZStd::string ToString(const SlotDataMap& map)
{
AZStd::string result;
for (const auto& iter : map)
{
result += iter.first.ToString();
result += ":";
result += iter.first.m_name;
result += " = ";
result += iter.second.m_datum.ToString();
result += ", ";
}
return result;
}
AZStd::string ToString(const VariableValues& variableValues)
{
AZStd::string result;
for (const auto& variableEntry : variableValues)
{
// <type> name = value,
result += "<";
result += variableEntry.second.second.ToString();
result += "> ";
result += variableEntry.second.first;
result += " = ";
result += variableEntry.second.second.m_datum.ToString();
result += ", ";
}
return result;
}
}
@@ -0,0 +1,687 @@
/*
* 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
#include "Core.h"
#include "Core/Datum.h"
#include "Core/Endpoint.h"
#include "Variable/GraphVariable.h"
#include "Core/NamedId.h"
#include <AzCore/Component/NamedEntityId.h>
#include <AzCore/EBus/EBus.h>
#if defined(SC_EXECUTION_TRACE_ENABLED)
#define SC_EXECUTION_TRACE_THREAD_BEGUN(arg) ;
#define SC_EXECUTION_TRACE_THREAD_ENDED(arg) ;
#define SC_EXECUTION_TRACE_GRAPH_ACTIVATED(arg) ScriptCanvas::ExecutionNotificationsBus::Broadcast(&ScriptCanvas::ExecutionNotifications::GraphActivated, arg);
#define SC_EXECUTION_TRACE_GRAPH_DEACTIVATED(arg) ScriptCanvas::ExecutionNotificationsBus::Broadcast(&ScriptCanvas::ExecutionNotifications::GraphDeactivated, arg);
#define SC_EXECUTION_TRACE_SIGNAL_DATA_OUTPUT(node, arg) if (node.GetRuntimeBus()->IsGraphObserved()) { ScriptCanvas::ExecutionNotificationsBus::Broadcast(&ScriptCanvas::ExecutionNotifications::NodeSignaledDataOuput, arg); }
#define SC_EXECUTION_TRACE_SIGNAL_INPUT(node, arg) if (node.GetRuntimeBus()->IsGraphObserved()) { ScriptCanvas::ExecutionNotificationsBus::Broadcast(&ScriptCanvas::ExecutionNotifications::NodeSignaledInput, arg); }
#define SC_EXECUTION_TRACE_SIGNAL_OUTPUT(node, arg) if (node.GetRuntimeBus()->IsGraphObserved()) { ScriptCanvas::ExecutionNotificationsBus::Broadcast(&ScriptCanvas::ExecutionNotifications::NodeSignaledOutput, arg); }
#define SC_EXECUTION_TRACE_VARIABLE_CHANGE(id, arg) if (GetRuntimeBus()->IsGraphObserved()) { ScriptCanvas::ExecutionNotificationsBus::Broadcast(&ScriptCanvas::ExecutionNotifications::VariableChanged, arg); }
#define SC_EXECUTION_TRACE_ANNOTATE_NODE(node, arg) if (node.GetRuntimeBus()->IsGraphObserved()) { ScriptCanvas::ExecutionNotificationsBus::Broadcast(&ScriptCanvas::ExecutionNotifications::AnnotateNode, arg); }
#else
#define SC_EXECUTION_TRACE_THREAD_BEGUN(arg) ;
#define SC_EXECUTION_TRACE_THREAD_ENDED(arg) ;
#define SC_EXECUTION_TRACE_GRAPH_ACTIVATED(arg) ;
#define SC_EXECUTION_TRACE_GRAPH_DEACTIVATED(arg) ;
#define SC_EXECUTION_TRACE_SIGNAL_DATA_OUTPUT(node, arg) ;
#define SC_EXECUTION_TRACE_SIGNAL_INPUT(node, arg) ;
#define SC_EXECUTION_TRACE_SIGNAL_OUTPUT(node, arg) ;
#define SC_EXECUTION_TRACE_VARIABLE_CHANGE(id, arg) ;
#define SC_EXECUTION_TRACE_ANNOTATE_NODE(node, arg) ;
#endif
namespace AZ
{
class ReflectContext;
}
namespace ScriptCanvas
{
struct GraphIdentifier final
{
AZ_CLASS_ALLOCATOR(GraphIdentifier, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(GraphIdentifier, "{0DAFC7EF-D23A-4353-8DA5-7D0CC186D8E3}");
AZ::ComponentId m_componentId = 0;
AZ::Data::AssetId m_assetId;
GraphIdentifier() = default;
GraphIdentifier(const AZ::Data::AssetId assetId, const AZ::ComponentId& componentId)
: m_componentId(componentId)
, m_assetId(assetId)
{}
bool operator==(const GraphIdentifier& other) const;
AZStd::string ToString() const;
};
struct GraphInfo
{
AZ_CLASS_ALLOCATOR(GraphInfo, AZ::SystemAllocator, 0);
AZ_RTTI(GraphInfo, "{8D40A70D-3846-46B4-B0BF-22B5D0F55ADC}");
NamedActiveEntityId m_runtimeEntity;
GraphIdentifier m_graphIdentifier;
GraphInfo() = default;
virtual ~GraphInfo() = default;
GraphInfo(const GraphInfo&) = default;
GraphInfo(const NamedActiveEntityId& runtimeEntity, const GraphIdentifier& graphIdentifier)
: m_runtimeEntity(runtimeEntity)
, m_graphIdentifier(graphIdentifier)
{}
bool operator==(const GraphInfo& graphInfo) const;
AZStd::string ToString() const;
};
struct VariableIdentifier
{
AZ_CLASS_ALLOCATOR(VariableIdentifier, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(VariableIdentifier, "{7DC089F4-B3D7-4F85-AA88-D215DF3C6831}");
VariableId m_variableId;
GraphIdentifier m_graphId;
VariableIdentifier() = default;
VariableIdentifier(VariableId variableId, const GraphIdentifier& graphId)
: m_variableId(variableId)
, m_graphId(graphId)
{}
AZStd::string ToString() const;
};
}
namespace AZStd
{
template<>
struct hash<ScriptCanvas::GraphIdentifier>
{
using argument_type = ScriptCanvas::GraphIdentifier;
using result_type = AZStd::size_t;
AZ_FORCE_INLINE size_t operator()(const argument_type& argument) const
{
AZStd::size_t graphIdentifierHash = AZStd::hash<AZ::Data::AssetId>()(argument.m_assetId);
AZStd::hash_combine(graphIdentifierHash, argument.m_componentId);
return graphIdentifierHash;
}
};
template<>
struct hash<ScriptCanvas::GraphInfo>
{
using argument_type = ScriptCanvas::GraphInfo;
using result_type = AZStd::size_t;
AZ_FORCE_INLINE size_t operator()(const argument_type& argument) const
{
AZStd::size_t graphInfoHash = AZStd::hash<AZ::EntityId>()(argument.m_runtimeEntity);
AZStd::hash_combine(graphInfoHash, argument.m_graphIdentifier);
return graphInfoHash;
}
};
}
namespace ScriptCanvas
{
using Timestamp = AZ::u64;
struct BreakTag
{
AZ_TYPE_INFO_LEGACY(BreakTag, "{B1B0976D-E300-470B-B01C-8EED7571414A}", );
static const char* ToString() { return "Break"; }
};
struct BreakpointTag
{
AZ_TYPE_INFO(BreakpointTag, "{4915585E-9AF7-4414-87D4-F1EE31E04E4D}");
static const char* ToString() { return "Breakpoint"; }
};
struct ContinueTag
{
AZ_TYPE_INFO(ContinueTag, "{611DF6CA-24CC-4F6B-89BF-4EDE56661040}");
static const char* ToString() { return "Continue"; }
};
struct ExecutionThreadBeginTag
{
AZ_TYPE_INFO(ExecutionThreadBeginTag, "{43C2F51D-17E9-4B4A-A1EF-3D5FD39857A4}");
static const char* ToString() { return "ExecutionThreadBegin"; }
};
struct ExecutionThreadEndTag
{
AZ_TYPE_INFO(ExecutionThreadEndTag, "{1BD155E9-ED07-4900-A6C9-04704A79424B}");
static const char* ToString() { return "ExecutionThreadEnd"; }
};
struct GetAvailableScriptTargetsTag
{
AZ_TYPE_INFO(GetAvailableScriptTargetsTag, "{D6B4D3FE-5975-4974-8DF4-CF823CCEEDB9}");
static const char* ToString() { return "GetAvailableScriptTargets"; }
};
struct GetActiveEntitiesTag
{
AZ_TYPE_INFO(GetActiveEntitiesTag, "{F28305CE-7CC4-4481-BCAA-5347361496B1}");
static const char* ToString() { return "GetActiveEntities"; }
};
struct GetActiveGraphsTag
{
AZ_TYPE_INFO(GetActiveGraphsTag, "{4AF50B18-87A7-45F0-925C-76D89DFC6DB6}");
static const char* ToString() { return "GetActiveGraphs"; }
};
struct GetVariableValueTag
{
AZ_TYPE_INFO(GetVariableValueTag, "{DBD77ADA-B8A5-423F-8524-5F2C765A1E46}");
static const char* ToString() { return "GetVariableValueTag"; }
};
struct GetVariableValuesTag
{
AZ_TYPE_INFO(GetVariableValuesTag, "{AEBE5DB8-DD6D-4B3F-AFDA-5A89010C21DF}");
static const char* ToString() { return "GetVariableValuesTag"; }
};
struct GraphActivationTag
{
AZ_TYPE_INFO(GraphActivationTag, "{9DC4188F-52A1-4F95-A20C-FEFECDF48FEE}");
static const char* ToString() { return "GraphActivation"; }
};
struct GraphDeactivationTag
{
AZ_TYPE_INFO(GraphDeactivationTag, "{FE4B8C6B-B8EE-4CA1-A4D4-DB559D977E22}");
static const char* ToString() { return "GraphDeactivation"; }
};
struct InputSignalTag
{
AZ_TYPE_INFO(InputSignalTag, "{AFAE431F-4E4F-4AC6-8EBB-5D6A209280A4}");
static const char* ToString() { return "InputSignal"; }
};
struct OutputSignalTag
{
AZ_TYPE_INFO(OutputSignalTag, "{6E8D6FA8-92C5-4EEB-82DE-8CF4293F83E6}");
static const char* ToString() { return "OutputSignal"; }
};
struct AnnotateNodeSignalTag
{
AZ_TYPE_INFO(AnnotateNodeSignalTag, "{6F61974F-B1BB-4377-8903-B360C50A28EC}");
static const char* ToString() { return "AnnotateNodeSignal"; }
};
struct StepOverTag
{
AZ_TYPE_INFO_LEGACY(StepOverTag, "{44980605-0FF2-4A5C-870E-324B4184ADD6}", );
static const char* ToString() { return "StepOver"; }
};
struct VariableChangeTag
{
AZ_TYPE_INFO(VariableChangeTag, "{2936D848-1EA1-4B07-A462-F52F8A0ED395}");
static const char* ToString() { return "VariableChange"; }
};
class LoggableEventVisitor;
struct LoggableEvent
{
public:
AZ_CLASS_ALLOCATOR(LoggableEvent, AZ::SystemAllocator, 0);
AZ_RTTI(LoggableEvent, "{0ACA3F48-170F-4859-9ED7-9C60523758A7}");
virtual ~LoggableEvent() = default;
virtual LoggableEvent* Duplicate() const = 0;
virtual Timestamp GetTimestamp() const = 0;
virtual void SetTimestamp(Timestamp) = 0;
virtual AZStd::string ToString() const = 0;
virtual void Visit(LoggableEventVisitor& visitor) = 0;
};
template<typename t_Tag, typename t_Parent>
struct TaggedParent
: public t_Parent
, public LoggableEvent
{
using ThisType = TaggedParent<t_Tag, t_Parent>;
AZ_CLASS_ALLOCATOR(ThisType, AZ::SystemAllocator, 0);
AZ_RTTI(((TaggedParent<t_Tag, t_Parent>), "{CF75CEEE-2305-49D4-AD41-407E82F819D7}", t_Tag, t_Parent), t_Parent, LoggableEvent);
static void Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<ThisType, t_Parent, LoggableEvent>()
->Version(0)
->Field("timestamp", &ThisType::m_timestamp)
;
}
}
Timestamp m_timestamp = 0;
TaggedParent()
: m_timestamp(AZStd::GetTimeUTCMilliSecond())
{}
TaggedParent(const t_Parent& parent)
: t_Parent(parent)
, m_timestamp(AZStd::GetTimeUTCMilliSecond())
{}
LoggableEvent* Duplicate() const override
{
return aznew ThisType(*this);
}
Timestamp GetTimestamp() const override
{
return m_timestamp;
}
void SetTimestamp(Timestamp timestamp) override
{
m_timestamp = timestamp;
}
AZStd::string ToString() const override
{
return AZStd::string::format("%s:%s", t_Tag::ToString(), t_Parent::ToString().data());
}
void Visit(LoggableEventVisitor& visitor) override;
};
struct ActiveGraphStatus final
{
AZ_CLASS_ALLOCATOR(ActiveGraphStatus, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(ActiveGraphStatus, "{6E251A99-EE03-4C12-9122-35A90CBB5891}");
int m_instanceCounter = 0;
bool m_isObserved = false;
};
using ActiveGraphStatusMap = AZStd::unordered_map< AZ::Data::AssetId, ActiveGraphStatus >;
using EntityActiveGraphStatusMap = AZStd::unordered_map< GraphIdentifier, ActiveGraphStatus >;
struct ActiveEntityStatus final
{
AZ_CLASS_ALLOCATOR(ActiveEntityStatus, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(ActiveEntityStatus, "{7D6013B6-142F-446B-9995-54C84EF64F7B}");
AZ::NamedEntityId m_namedEntityId;
EntityActiveGraphStatusMap m_activeGraphs;
};
using ActiveEntityStatusMap = AZStd::unordered_map< AZ::EntityId, ActiveEntityStatus >;
using ActiveEntitiesAndGraphs = AZStd::pair<ActiveEntityStatusMap, ActiveGraphStatusMap>;
struct DatumValue
{
AZ_CLASS_ALLOCATOR(DatumValue, AZ::SystemAllocator, 0);
AZ_RTTI(DatumValue, "{5B4C8EA8-747E-4557-A10A-0EA0ADB387CA}");
static DatumValue Create(const GraphVariable& value);
// if valid, the datum will contain a string result of BCO->ToString()
AZ::TypeId m_behaviorContextObjectType;
Datum m_datum;
DatumValue() = default;
virtual ~DatumValue() = default;
DatumValue(const DatumValue&) = default;
DatumValue(AZ::TypeId behaviorContextObjectType, const AZStd::string& toStringResult)
: m_behaviorContextObjectType(behaviorContextObjectType)
, m_datum(Datum(toStringResult))
{}
DatumValue(const Datum& datum)
: m_behaviorContextObjectType{}
, m_datum(datum)
{}
AZStd::string ToString() const;
};
using SlotDataMap = AZStd::unordered_map<NamedSlotId, DatumValue>;
using VariableValues = AZStd::unordered_map<VariableId, AZStd::pair<AZStd::string, DatumValue>>;
struct ActivationInfo
: public GraphInfo
{
AZ_CLASS_ALLOCATOR(ActivationInfo, AZ::SystemAllocator, 0);
AZ_RTTI(ActivationInfo, "{9EBCB557-80D1-43CA-840E-BB8945BF13F4}", GraphInfo);
bool m_entityIsObserved = false;
VariableValues m_variableValues;
ActivationInfo() = default;
virtual ~ActivationInfo() = default;
ActivationInfo(const ActivationInfo&) = default;
ActivationInfo(const GraphInfo& info);
ActivationInfo(const GraphInfo& info, const VariableValues& variableValues);
AZStd::string ToString() const;
};
struct Signal
: public GraphInfo
{
AZ_CLASS_ALLOCATOR(Signal, AZ::SystemAllocator, 0);
AZ_RTTI(Signal, "{F65B92D1-10D8-4065-90FA-8FD46A9B122A}", GraphInfo);
NodeTypeIdentifier m_nodeType;
NamedEndpoint m_endpoint;
SlotDataMap m_data;
Signal() = default;
Signal(const Signal& signal) = default;
Signal(const GraphInfo& graphInfo, const NodeTypeIdentifier& nodeType, const NamedEndpoint& endpoint)
: GraphInfo(graphInfo)
, m_nodeType(nodeType)
, m_endpoint(endpoint)
{}
Signal(const GraphInfo& graphInfo, const NodeTypeIdentifier& nodeType, const NamedEndpoint& endpoint, const SlotDataMap& data)
: GraphInfo(graphInfo)
, m_nodeType(nodeType)
, m_endpoint(endpoint)
, m_data(data)
{}
virtual ~Signal() = default;
bool operator==(const Signal& other) const;
AZStd::string ToString() const;
};
template<typename t_Tag>
struct TaggedDataValue
: public DatumValue
, public GraphInfo
, public LoggableEvent
{
using ThisType = TaggedDataValue<t_Tag>;
AZ_CLASS_ALLOCATOR(TaggedDataValue<t_Tag>, AZ::SystemAllocator, 0);
AZ_RTTI(((TaggedDataValue<t_Tag>), "{893B73BA-E1CC-4D91-92D1-C1CF46817A57}", t_Tag), DatumValue, GraphInfo, LoggableEvent);
using DatumValue::DatumValue;
static void Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<ThisType, DatumValue, GraphInfo, LoggableEvent>()
->Version(0)
->Field("timestamp", &ThisType::m_timestamp)
;
}
}
Timestamp m_timestamp = 0;
TaggedDataValue()
: m_timestamp(AZStd::GetTimeUTCMilliSecond())
{}
TaggedDataValue(const TaggedDataValue&) = default;
TaggedDataValue(const GraphInfo& graphInfo, const DatumValue& dataValue)
: DatumValue(dataValue)
, GraphInfo(graphInfo)
, m_timestamp(AZStd::GetTimeUTCMilliSecond())
{}
//TaggedDataValue(const Signal& signal)
// : Signal(signal)
// , m_timestamp(AZStd::GetTimeUTCMilliSecond())
//{}
LoggableEvent* Duplicate() const override
{
return aznew TaggedDataValue<t_Tag>(*this);
}
Timestamp GetTimestamp() const override
{
return m_timestamp;
}
void SetTimestamp(Timestamp timestamp) override
{
m_timestamp = timestamp;
}
AZStd::string ToString() const override
{
return AZStd::string::format("%s %s %s", t_Tag::ToString(), DatumValue::ToString().data(), GraphInfo::ToString().data());
}
void Visit(LoggableEventVisitor& visitor) override;
};
using Breakpoint = TaggedParent<BreakpointTag, Signal>;
struct ExecutionThreadBeginning
: public GraphInfo
, public LoggableEvent
{
AZ_CLASS_ALLOCATOR(ExecutionThreadBeginning, AZ::SystemAllocator, 0);
AZ_RTTI(ExecutionThreadBeginning, "{410EB31A-F6DC-415D-848B-43537B962A43}", GraphInfo, LoggableEvent);
NamedActiveEntityId m_nodeId;
Timestamp m_timestamp;
ExecutionThreadBeginning();
ExecutionThreadBeginning(const ExecutionThreadBeginning&) = default;
ExecutionThreadBeginning(const GraphInfo& graphInfo, AZ::EntityId nodeId)
: GraphInfo(graphInfo)
, m_nodeId(nodeId)
{}
virtual ~ExecutionThreadBeginning() = default;
LoggableEvent* Duplicate() const override;
Timestamp GetTimestamp() const override;
void SetTimestamp(Timestamp timestamp) override;
AZStd::string ToString() const override;
void Visit(LoggableEventVisitor& visitor) override;
};
using ExecutionThreadEnd = TaggedParent<ExecutionThreadEndTag, GraphInfo>;
using GraphActivation = TaggedParent<GraphActivationTag, ActivationInfo>;
using GraphDeactivation = TaggedParent<GraphDeactivationTag, ActivationInfo>;
using InputSignal = TaggedParent<InputSignalTag, Signal>;
using OutputSignal = TaggedParent<OutputSignalTag, Signal>;
// Base class to handle some basic information
struct GraphInfoEventBase
: public GraphInfo
, public LoggableEvent
{
public:
AZ_CLASS_ALLOCATOR(GraphInfoEventBase, AZ::SystemAllocator, 0);
AZ_RTTI(GraphInfoEventBase, "{873431EB-7B4D-410A-9F2F-5E2E0E00140B}", GraphInfo, LoggableEvent);
GraphInfoEventBase();
GraphInfoEventBase(const GraphInfo& graphInfo);
Timestamp GetTimestamp() const override final;
void SetTimestamp(Timestamp timestamp) override final;
Timestamp m_timestamp;
};
struct NodeStateChange
: public GraphInfoEventBase
{
AZ_CLASS_ALLOCATOR(NodeStateChange, AZ::SystemAllocator, 0);
AZ_RTTI(NodeStateChange, "{6D3B9C70-E6E9-4780-87C0-D74E7BFBE53D}", GraphInfoEventBase);
NodeStateChange();
NodeStateChange(const NodeStateChange&) = default;
LoggableEvent* Duplicate() const override;
AZStd::string ToString() const override;
void Visit(LoggableEventVisitor& visitor) override;
};
using VariableChange = TaggedDataValue<VariableChangeTag>;
struct AnnotateNodeSignal
: public GraphInfoEventBase
{
public:
AZ_CLASS_ALLOCATOR(AnnotateNodeSignal, AZ::SystemAllocator, 0);
AZ_RTTI(AnnotateNodeSignal, "{EE13C14C-9EFA-47F6-9B23-900D71BC9DDE}", GraphInfoEventBase);
enum AnnotationLevel
{
Info,
Warning,
Error
};
AnnotateNodeSignal();
AnnotateNodeSignal(const AnnotateNodeSignal&) = default;
AnnotateNodeSignal(const GraphInfo& graphInfo, AnnotationLevel annotationLevel, AZStd::string_view annotation, const AZ::NamedEntityId& assetId);
LoggableEvent* Duplicate() const override;
AZStd::string ToString() const override;
void Visit(LoggableEventVisitor& visitor) override;
AnnotationLevel m_annotationLevel;
AZStd::string m_annotation;
AZ::NamedEntityId m_assetNodeId;
};
class OutputDataSignal
: public GraphInfoEventBase
{
public:
AZ_CLASS_ALLOCATOR(OutputDataSignal, AZ::SystemAllocator, 0);
AZ_RTTI(OutputDataSignal, "{CA05C19C-BE83-4158-9E28-36F1D55BD146}", GraphInfoEventBase);
OutputDataSignal() = default;
OutputDataSignal(const OutputDataSignal& outputDataSignal) = default;
OutputDataSignal(const GraphInfo& graphInfo, const NodeTypeIdentifier& nodeType, const NamedEndpoint& namedEndpoint, const DatumValue& value);
LoggableEvent* Duplicate() const override;
AZStd::string ToString() const override;
void Visit(LoggableEventVisitor& visitor) override;
NodeTypeIdentifier m_nodeType;
NamedEndpoint m_endpoint;
DatumValue m_outputValue;
};
class ExecutionNotifications
: public AZ::EBusTraits
{
public:
virtual void GraphActivated(const GraphActivation&) = 0;
virtual void GraphDeactivated(const GraphActivation&) = 0;
virtual bool IsNodeObserved(const Node&) = 0;
virtual bool IsVariableObserved(const VariableId&) = 0;
virtual void NodeSignaledOutput(const OutputSignal&) = 0;
virtual void NodeSignaledInput(const InputSignal&) = 0;
virtual void NodeSignaledDataOuput(const OutputDataSignal&) = 0;
virtual void NodeStateUpdated(const NodeStateChange&) = 0;
virtual void VariableChanged(const VariableChange&) = 0;
virtual void AnnotateNode(const AnnotateNodeSignal&) = 0;
};
using ExecutionNotificationsBus = AZ::EBus<ExecutionNotifications>;
class LoggableEventVisitor
{
public:
virtual ~LoggableEventVisitor() = default;
// used for logging
virtual void Visit(ExecutionThreadEnd&) = 0;
virtual void Visit(ExecutionThreadBeginning&) = 0;
virtual void Visit(GraphActivation&) = 0;
virtual void Visit(GraphDeactivation&) = 0;
virtual void Visit(NodeStateChange&) = 0;
virtual void Visit(InputSignal&) = 0;
virtual void Visit(OutputSignal&) = 0;
virtual void Visit(OutputDataSignal&) = 0;
virtual void Visit(VariableChange&) = 0;
virtual void Visit(AnnotateNodeSignal&) = 0;
// should never show up in logging
void Visit(Breakpoint&) {};
};
void ReflectExecutionBusArguments(AZ::ReflectContext* context);
AZStd::string ToString(const SlotDataMap& map);
AZStd::string ToString(const VariableValues& variableValues);
template<typename t_Tag, typename t_Parent>
void TaggedParent<t_Tag, t_Parent>::Visit(LoggableEventVisitor& visitor)
{
visitor.Visit(*this);
}
template<typename t_Tag>
void TaggedDataValue<t_Tag>::Visit(LoggableEventVisitor& visitor)
{
visitor.Visit(*this);
}
}
namespace AZStd
{
template<>
struct hash<ScriptCanvas::Breakpoint>
{
using argument_type = ScriptCanvas::Breakpoint;
using result_type = AZStd::size_t;
AZ_FORCE_INLINE size_t operator()(const argument_type& argument) const
{
result_type result = AZStd::hash<const AZ::u64>()(static_cast<AZ::u64>(argument.m_runtimeEntity));
AZStd::hash_combine(result, argument.m_graphIdentifier);
AZStd::hash_combine(result, argument.m_endpoint);
return result;
}
};
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,227 @@
/*
* 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
#include <AzCore/Component/Component.h>
#include <AzCore/Component/EntityBus.h>
#include <AzCore/Outcome/Outcome.h>
#include <AzCore/std/containers/stack.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/parallel/mutex.h>
#include <ScriptCanvas/Core/GraphBus.h>
#include <ScriptCanvas/Core/GraphData.h>
#include <ScriptCanvas/Debugger/Bus.h>
#include <ScriptCanvas/Execution/ErrorBus.h>
#include <ScriptCanvas/Execution/ExecutionContext.h>
#include <ScriptCanvas/Execution/RuntimeBus.h>
#include <ScriptCanvas/Debugger/StatusBus.h>
#include <ScriptCanvas/Debugger/ValidationEvents/ValidationEvent.h>
namespace ScriptCanvas
{
class Node;
class Slot;
class Connection;
class GraphVariableManagerRequests;
//! TODO: Remove the execution logic from this class and change all ScriptCanvas UnitTest to use the Runtime Component
//! Graph is the execution model of a ScriptCanvas graph.
class Graph
: public AZ::Component
, protected GraphRequestBus::Handler
, protected RuntimeRequestBus::Handler
, protected StatusRequestBus::Handler
, private AZ::EntityBus::Handler
{
private:
struct ValidationStruct
{
AZ::Crc32 m_validationEventId;
AZStd::string m_errorDescription;
};
public:
friend Node;
AZ_COMPONENT(Graph, "{C3267D77-EEDC-490E-9E42-F1D1F473E184}");
static void Reflect(AZ::ReflectContext* context);
Graph(const ScriptCanvasId& executionId = AZ::Entity::MakeId());
~Graph() override;
void Init() override;
void Activate() override;
void Deactivate() override;
const AZStd::vector<AZ::EntityId> GetNodesConst() const;
AZStd::unordered_set<AZ::Entity*>& GetNodeEntities() { return m_graphData.m_nodes; }
const AZStd::unordered_set<AZ::Entity*>& GetNodeEntities() const { return m_graphData.m_nodes; }
const ScriptCanvas::ScriptCanvasId& GetScriptCanvasId() const { return m_scriptCanvasId; }
//// GraphRequestBus::Handler
bool AddNode(const AZ::EntityId&) override;
bool RemoveNode(const AZ::EntityId& nodeId) override;
Node* FindNode(AZ::EntityId nodeID) const override;
AZStd::vector<AZ::EntityId> GetNodes() const override;
Slot* FindSlot(const Endpoint& endpoint) const override;
bool AddConnection(const AZ::EntityId&) override;
bool RemoveConnection(const AZ::EntityId& connectionId) override;
AZStd::vector<AZ::EntityId> GetConnections() const override;
AZStd::vector<Endpoint> GetConnectedEndpoints(const Endpoint& firstEndpoint) const override;
AZStd::pair< EndpointMapConstIterator, EndpointMapConstIterator > GetConnectedEndpointIterators(const Endpoint& endpoint) const override;
bool IsEndpointConnected(const Endpoint& endpoint) const override;
bool FindConnection(AZ::Entity*& connectionEntity, const Endpoint& firstEndpoint, const Endpoint& otherEndpoint) const override;
bool Connect(const AZ::EntityId& sourceNodeId, const SlotId& sourceSlotId, const AZ::EntityId& targetNodeId, const SlotId& targetSlotId) override;
bool Disconnect(const AZ::EntityId& sourceNodeId, const SlotId& sourceSlotId, const AZ::EntityId& targetNodeId, const SlotId& targetSlotId) override;
bool ConnectByEndpoint(const Endpoint& sourceEndpoint, const Endpoint& targetEndpoint) override;
AZ::Outcome<void, AZStd::string> CanCreateConnectionBetween(const Endpoint& sourceEndpoint, const Endpoint& targetEndpoint) const override;
AZ::Outcome<void, AZStd::string> CanConnectionExistBetween(const Endpoint& sourceEndpoint, const Endpoint& targetEndpoint) const override;
bool DisconnectByEndpoint(const Endpoint& sourceEndpoint, const Endpoint& targetEndpoint) override;
bool DisconnectById(const AZ::EntityId& connectionId) override;
// Dependent Assets
bool AddDependentAsset(AZ::EntityId nodeId, const AZ::TypeId assetType, const AZ::Data::AssetId assetId) override;
bool RemoveDependentAsset(AZ::EntityId nodeId) override;
//! Retrieves the Entity this Graph component is currently located on
//! NOTE: There can be multiple Graph components on the same entity so calling FindComponent may not not return this GraphComponent
AZ::Entity* GetGraphEntity() const override { return GetEntity(); }
Graph* GetGraph() { return this; }
GraphData* GetGraphData() override { return &m_graphData; }
const GraphData* GetGraphDataConst() const override { return &m_graphData; }
const VariableData* GetVariableDataConst() const { return const_cast<Graph*>(this)->GetVariableData(); }
bool AddGraphData(const GraphData&) override;
void RemoveGraphData(const GraphData&) override;
bool IsBatchAddingGraphData() const override;
AZStd::unordered_set<AZ::Entity*> CopyItems(const AZStd::unordered_set<AZ::Entity*>& entities) override;
void AddItems(const AZStd::unordered_set<AZ::Entity*>& graphField) override;
void RemoveItems(const AZStd::unordered_set<AZ::Entity*>& graphField) override;
void RemoveItems(const AZStd::vector<AZ::Entity*>& graphField);
AZStd::unordered_set<AZ::Entity*> GetItems() const override;
bool AddItem(AZ::Entity* itemRef) override;
bool RemoveItem(AZ::Entity* itemRef) override;
///////////////////////////////////////////////////////////
// StatusRequestBus
void ValidateGraph(ValidationResults& validationEvents);
////
virtual void ReportError(const Node& node, const AZStd::string& errorSource, const AZStd::string& errorMessage);
bool IsInErrorState() const { return m_executionContext.IsInErrorState(); }
bool IsInIrrecoverableErrorState() const { return m_executionContext.IsInErrorState(); }
AZStd::string_view GetLastErrorDescription() const { return m_executionContext.GetLastErrorDescription(); }
protected:
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
(void)dependent;
}
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("ScriptCanvasRuntimeService", 0x776e1e3a));;
}
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("ScriptCanvasService", 0x41fd58f3));
}
void PostActivate();
void ValidateVariables(ValidationResults& validationResults);
void ValidateScriptEvents(ValidationResults& validationResults);
bool ValidateConnectionEndpoints(const AZ::EntityId& connectionRef, const AZStd::unordered_set<AZ::EntityId>& nodeRefs);
AZ::Outcome<void, AZStd::vector<ValidationStruct> > ValidateNode(AZ::Entity* nodeEntity, ValidationResults& validationEvents) const;
AZ::Outcome<void, ValidationStruct> ValidateConnection(AZ::Entity* connection) const;
AZ::Outcome<void, ValidationStruct> ValidateExecutionConnection(const Node& sourceNode, const Slot& sourceSlot, const Node& targetNode, const Slot& targetSlot) const;
AZ::Outcome<void, ValidationStruct> ValidateDataConnection(const Node& sourceNode, const Slot& sourceSlot, const Node& targetNode, const Slot& targetSlot) const;
bool IsInDataFlowPath(const Node* sourceNode, const Node* targetNode) const;
void RefreshConnectionValidity(bool warnOnRemoval = false);
//// RuntimeRequestBus::Handler
AZ::Data::AssetId GetAssetId() const override { return AZ::Data::AssetId(); }
GraphIdentifier GetGraphIdentifier() const override { return GraphIdentifier(GetAssetId(), 0); }
AZStd::string GetAssetName() const override { return ""; }
AZ::EntityId GetRuntimeEntityId() const override { return GetEntity() ? GetEntityId() : AZ::EntityId(); }
VariableId FindAssetVariableIdByRuntimeVariableId(VariableId runtimeId) const override { return runtimeId; }
VariableId FindRuntimeVariableIdByAssetVariableId(VariableId assetId) const override { return assetId; }
AZ::EntityId FindAssetNodeIdByRuntimeNodeId(AZ::EntityId editorNode) const override { return editorNode; }
AZ::EntityId FindRuntimeNodeIdByAssetNodeId(AZ::EntityId runtimeNode) const override { return runtimeNode; }
VariableData* GetVariableData() override;
const GraphVariableMapping* GetVariables() const override;
GraphVariable* FindVariable(AZStd::string_view propName) override;
GraphVariable* FindVariableById(const VariableId& variableId) override;
Data::Type GetVariableType(const VariableId& variableId) const override;
AZStd::string_view GetVariableName(const VariableId& variableId) const override;
bool IsGraphObserved() const override;
void SetIsGraphObserved(bool isObserved) override;
AZ::Data::AssetType GetAssetType() const override;
////
const AZStd::unordered_map<AZ::EntityId, Node* >& GetNodeMapping() const { return m_nodeMapping; }
protected:
void VersioningRemoveSlot(ScriptCanvas::Node& scriptCanvasNode, const SlotId& slotId);
GraphData m_graphData;
AZ::Data::AssetType m_assetType;
private:
ScriptCanvasId m_scriptCanvasId;
ExecutionContext m_executionContext;
GraphVariableManagerRequests* m_variableRequests = nullptr;
// Keeps a mapping of the Node EntityId -> NodeComponent.
// Saves looking up the NodeComponent everytime we need the Node.
AZStd::unordered_map<AZ::EntityId, Node* > m_nodeMapping;
bool m_isObserved;
bool m_batchAddingData;
void OnEntityActivated(const AZ::EntityId&) override;
class GraphEventHandler;
};
}
@@ -0,0 +1,185 @@
/*
* 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
#include "Core.h"
#include "Endpoint.h"
#include <ScriptCanvas/Variable/VariableCore.h>
#include <AzCore/EBus/EBus.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Outcome/Outcome.h>
namespace ScriptCanvas
{
struct GraphData;
class Graph;
class Slot;
//! These are public graph requests
class GraphRequests : public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = ScriptCanvasId;
//! Add a ScriptCanvas Node to the Graph
virtual bool AddNode(const AZ::EntityId&) = 0;
//! Remove a ScriptCanvas Node to the Graph
virtual bool RemoveNode(const AZ::EntityId& nodeId) = 0;
//! Add a ScriptCanvas Connection to the Graph
virtual bool AddConnection(const AZ::EntityId&) = 0;
//! Remove a ScriptCanvas Connection from the Graph
virtual bool RemoveConnection(const AZ::EntityId& nodeId) = 0;
//! Add an asset dependency to the Graph
virtual bool AddDependentAsset(AZ::EntityId nodeId, const AZ::TypeId assetType, const AZ::Data::AssetId assetId) = 0;
//! Remove an asset dependency from the Graph
virtual bool RemoveDependentAsset(AZ::EntityId nodeId) = 0;
virtual AZStd::vector<AZ::EntityId> GetNodes() const = 0;
virtual AZStd::vector<AZ::EntityId> GetConnections() const = 0;
virtual AZStd::vector<Endpoint> GetConnectedEndpoints(const Endpoint& firstEndpoint) const = 0;
virtual bool FindConnection(AZ::Entity*& connectionEntity, const Endpoint& firstEndpoint, const Endpoint& otherEndpoint) const = 0;
virtual Slot* FindSlot(const Endpoint& endpoint) const = 0;
//! Retrieves the Entity this Graph component is located on
//! NOTE: There can be multiple Graph components on the same entity so calling FindComponent may not not return this GraphComponent
virtual AZ::Entity* GetGraphEntity() const = 0;
//! Retrieves the Graph Component directly using the BusId
virtual Graph* GetGraph() = 0;
virtual bool Connect(const AZ::EntityId& sourceNodeId, const SlotId& sourceSlot, const AZ::EntityId& targetNodeId,const SlotId& targetSlot) = 0;
virtual bool Disconnect(const AZ::EntityId& sourceNodeId, const SlotId& sourceSlot, const AZ::EntityId& targetNodeId, const SlotId& targetSlot) = 0;
virtual bool ConnectByEndpoint(const Endpoint& sourceEndpoint, const Endpoint& targetEndpoint) = 0;
//! Returns whether or not a new connecion can be created between two connections.
//! This will take into account if the endpoints are already connected
virtual AZ::Outcome<void, AZStd::string> CanCreateConnectionBetween(const Endpoint& sourceEndpoint, const Endpoint& targetEndpoint) const = 0;
//! Returns whether or not a connection could exist between the two connections.
//! Does not take into account if the endpoints are already connected.
virtual AZ::Outcome<void, AZStd::string> CanConnectionExistBetween(const Endpoint& sourceEndpoint, const Endpoint& targetEndpoint) const = 0;
virtual bool DisconnectByEndpoint(const Endpoint& sourceEndpoint, const Endpoint& targetEndpoint) = 0;
virtual bool DisconnectById(const AZ::EntityId& connectionId) = 0;
//! Copies any Node and Connection Entities that belong to the graph to a GraphSerializableField
virtual AZStd::unordered_set<AZ::Entity*> CopyItems(const AZStd::unordered_set<AZ::Entity*>& entities) = 0;
//! Adds any Node and Connection Entities to the graph
virtual void AddItems(const AZStd::unordered_set<AZ::Entity*>& entities) = 0;
//! Removes any Node and Connection Entities that belong to the graph
virtual void RemoveItems(const AZStd::unordered_set<AZ::Entity*>& entities) = 0;
//! Retrieves any entities that can be be added to graphs
virtual AZStd::unordered_set<AZ::Entity*> GetItems() const = 0;
//! Add item to graph if the item is of the type that can be added to the graph
virtual bool AddItem(AZ::Entity* itemEntity) = 0;
//! Remove item if it is on the graph
virtual bool RemoveItem(AZ::Entity* itemEntity) = 0;
//! Retrieves a pointer the GraphData structure stored on the graph
virtual GraphData* GetGraphData() = 0;
virtual const GraphData* GetGraphDataConst() const = 0;
// Adds nodes and connections in the GraphData structure to the graph
virtual bool AddGraphData(const GraphData&) = 0;
// Removes nodes and connections in the GraphData structure from the graph
virtual void RemoveGraphData(const GraphData&) = 0;
// Signals wether or not a batch of graph data is being added and some extra steps are needed
// to maintain data integrity for dynamic nodes
virtual bool IsBatchAddingGraphData() const = 0;
virtual void SetIsGraphObserved(bool observed) = 0;
virtual bool IsGraphObserved() const = 0;
};
using GraphRequestBus = AZ::EBus<GraphRequests>;
class GraphNotifications : public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = ScriptCanvasId;
//! Notification when a node is added
virtual void OnNodeAdded(const AZ::EntityId&) {}
//! Notification when a node is removed
virtual void OnNodeRemoved(const AZ::EntityId&) {}
//! Notification when a connection is added
virtual void OnConnectionAdded(const AZ::EntityId&) {}
//! Notification when a connections is removed
virtual void OnConnectionRemoved(const AZ::EntityId&) {}
//! Notification when a batch add for a graph begins
virtual void OnBatchAddBegin() {}
//! Notification when a batch add for a graph completes
virtual void OnBatchAddComplete() {};
};
using GraphNotificationBus = AZ::EBus<GraphNotifications>;
class GraphConfigurationRequests : public AZ::ComponentBus
{
public:
virtual const ScriptCanvas::ScriptCanvasId& GetScriptCanvasId() const = 0;
};
using GraphConfigurationRequestBus = AZ::EBus<GraphConfigurationRequests>;
// This bus is for anything co-components that needs to be configured with the graph.
class GraphConfigurationNotifications : public AZ::ComponentBus
{
public:
virtual void ConfigureScriptCanvasId(const ScriptCanvas::ScriptCanvasId& scriptCanvasId) = 0;
};
using GraphConfigurationNotificationBus = AZ::EBus<GraphConfigurationNotifications>;
class EndpointNotifications : public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = Endpoint;
//! Notification when an endpoint has been connected.
//! \param the target Endpoint. The source Endpoint can be obtained using EndpointNotificationBus::GetCurrentBusId().
virtual void OnEndpointConnected([[maybe_unused]] const Endpoint& targetEndpoint) {}
//! Notification when an endpoint has been disconnected.
//! \param the target Endpoint. The source Endpoint can be obtained using EndpointNotificationBus::GetCurrentBusId().
virtual void OnEndpointDisconnected([[maybe_unused]] const Endpoint& targetEndpoint) {}
//! Notification when an endpoint has it's reference changed.
virtual void OnEndpointReferenceChanged([[maybe_unused]] const VariableId& variableId) {}
virtual void OnEndpointConvertedToReference() {}
virtual void OnEndpointConvertedToValue() {}
virtual void OnSlotRecreated() {};
};
using EndpointNotificationBus = AZ::EBus<EndpointNotifications>;
}
@@ -0,0 +1,222 @@
/*
* 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 <AzCore/Component/EntityUtils.h>
#include <ScriptCanvas/Core/Connection.h>
#include <ScriptCanvas/Core/GraphData.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AZ
{
class Entity;
}
namespace ScriptCanvas
{
class GraphDataEventHandler : public AZ::SerializeContext::IEventHandler
{
public:
/// Called to rebuild the Endpoint map
void OnWriteEnd(void* classPtr) override
{
auto* graphData = reinterpret_cast<GraphData*>(classPtr);
graphData->BuildEndpointMap();
graphData->LoadDependentAssets();
}
};
void GraphData::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
// On-demand reflect the previously used unordered_set to ensure the version converter works.
using DependentAssetSet = AZStd::unordered_set<AZStd::tuple<AZ::EntityId, AZ::TypeId, AZ::Data::AssetId>>;
auto genericInfo = AZ::SerializeGenericTypeInfo<DependentAssetSet>::GetGenericInfo();
genericInfo->Reflect(serializeContext);
serializeContext->Class<GraphData>()
->Version(4, &GraphData::VersionConverter)
->EventHandler<GraphDataEventHandler>()
->Field("m_nodes", &GraphData::m_nodes)
->Field("m_connections", &GraphData::m_connections)
->Field("m_dependentAssets", &GraphData::m_dependentAssets)
->Field("m_scriptEventAssets", &GraphData::m_scriptEventAssets)
;
}
}
bool GraphData::VersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& rootElement)
{
enum
{
FixedDependentAssetContainerType = 3
};
if (rootElement.GetVersion() == 0)
{
int connectionsIndex = rootElement.FindElement(AZ_CRC("m_connections", 0xdc357426));
if (connectionsIndex < 0)
{
return false;
}
AZ::SerializeContext::DataElementNode& entityElement = rootElement.GetSubElement(connectionsIndex);
AZStd::unordered_set<AZ::Entity*> entitiesSet;
if (!entityElement.GetData(entitiesSet))
{
return false;
}
AZStd::vector<AZ::Entity*> entitiesVector(entitiesSet.begin(), entitiesSet.end());
rootElement.RemoveElement(connectionsIndex);
if (rootElement.AddElementWithData(context, "m_connections", entitiesVector) == -1)
{
return false;
}
for (AZ::Entity* entity : entitiesSet)
{
delete entity;
}
}
if (rootElement.GetVersion() < FixedDependentAssetContainerType)
{
using DependentAssetSet = AZStd::unordered_set<AZStd::tuple<AZ::EntityId, AZ::TypeId, AZ::Data::AssetId>>;
int dependentAssetsIndex = rootElement.FindElement(AZ_CRC("m_dependentAssets", 0xfd314be4));
if (dependentAssetsIndex < 0)
{
return true;
}
AZ::SerializeContext::DataElementNode& dataElement = rootElement.GetSubElement(dependentAssetsIndex);
DependentAssetSet dependentAssetSet;
DependentAssets dependentAssetMap{};
if (dataElement.GetData(dependentAssetSet))
{
for (const auto& entry : dependentAssetSet)
{
if (dependentAssetMap.find(AZStd::get<2>(entry)) == dependentAssetMap.end())
{
dependentAssetMap[AZStd::get<2>(entry)] = AZStd::make_pair(AZStd::get<0>(entry), AZStd::get<1>(entry));
}
}
}
// Remove the old version
rootElement.RemoveElement(dependentAssetsIndex);
if (!dependentAssetMap.empty())
{
if (rootElement.AddElementWithData(context, "m_dependentAssets", dependentAssetMap) == -1)
{
return false;
}
}
}
return true;
}
GraphData::GraphData(GraphData&& other)
: m_nodes(AZStd::move(other.m_nodes))
, m_connections(AZStd::move(other.m_connections))
, m_endpointMap(AZStd::move(other.m_endpointMap))
, m_dependentAssets(AZStd::move(other.m_dependentAssets))
, m_scriptEventAssets(AZStd::move(other.m_scriptEventAssets))
{
other.m_nodes.clear();
other.m_connections.clear();
other.m_endpointMap.clear();
other.m_dependentAssets.clear();
other.m_scriptEventAssets.clear();
}
GraphData& GraphData::operator=(GraphData&& other)
{
if (this != &other)
{
m_nodes = AZStd::move(other.m_nodes);
m_connections = AZStd::move(other.m_connections);
m_endpointMap = AZStd::move(other.m_endpointMap);
m_dependentAssets = AZStd::move(other.m_dependentAssets);
m_scriptEventAssets = AZStd::move(other.m_scriptEventAssets);
other.m_nodes.clear();
other.m_connections.clear();
other.m_endpointMap.clear();
other.m_dependentAssets.clear();
other.m_scriptEventAssets.clear();
}
return *this;
}
void GraphData::BuildEndpointMap()
{
m_endpointMap.clear();
for (auto& connectionEntity : m_connections)
{
auto* connection = connectionEntity ? AZ::EntityUtils::FindFirstDerivedComponent<Connection>(connectionEntity) : nullptr;
if (connection)
{
m_endpointMap.emplace(connection->GetSourceEndpoint(), connection->GetTargetEndpoint());
m_endpointMap.emplace(connection->GetTargetEndpoint(), connection->GetSourceEndpoint());
}
}
}
void GraphData::Clear(bool deleteData)
{
if (deleteData)
{
for (auto& nodeRef : m_nodes)
{
delete nodeRef;
}
for (auto& connectionRef : m_connections)
{
delete connectionRef;
}
}
m_endpointMap.clear();
m_nodes.clear();
m_connections.clear();
m_dependentAssets.clear();
m_scriptEventAssets.clear();
}
void GraphData::LoadDependentAssets()
{
// For version conversion purposes only
for (auto& assetData : m_dependentAssets)
{
AZ::Data::Asset<AZ::Data::AssetData> asset = AZ::Data::AssetManager::Instance().GetAsset(assetData.first, assetData.second.second, AZ::Data::AssetLoadBehavior::Default);
asset.BlockUntilLoadComplete();
if (asset.GetStatus() == AZ::Data::AssetData::AssetStatus::Error)
{
AZ_Error("Script Canvas", false, "Error loading dependent asset with ID: %s", asset.GetId().ToString<AZStd::string>().c_str());
}
if (asset.GetType() == azrtti_typeid<ScriptEvents::ScriptEventsAsset>())
{
m_scriptEventAssets.push_back(AZStd::make_pair(assetData.second.first, asset));
}
}
m_dependentAssets.clear();
}
}
@@ -0,0 +1,61 @@
/*
* 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
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/containers/unordered_map.h>
#include <ScriptCanvas/Core/Endpoint.h>
#include <ScriptEvents/ScriptEventsAsset.h>
namespace AZ
{
class Entity;
}
namespace ScriptCanvas
{
//! Structure for maintaining GraphData
struct GraphData
{
AZ_TYPE_INFO(GraphData, "{ADCB5EB5-8D3F-42ED-8F65-EAB58A82C381}");
AZ_CLASS_ALLOCATOR(GraphData, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* context);
GraphData() = default;
GraphData(const GraphData&) = default;
GraphData& operator=(const GraphData&) = default;
GraphData(GraphData&&);
GraphData& operator=(GraphData&&);
void BuildEndpointMap();
void Clear(bool deleteData = false);
void LoadDependentAssets();
using NodeContainer = AZStd::unordered_set<AZ::Entity*>;
using ConnectionContainer = AZStd::vector<AZ::Entity*>;
using DependentScriptEvent = AZStd::vector<AZStd::pair<AZ::EntityId, ScriptEvents::ScriptEventsAssetPtr>>;
NodeContainer m_nodes;
ConnectionContainer m_connections;
DependentScriptEvent m_scriptEventAssets;
using DependentAssets = AZStd::unordered_map<AZ::Data::AssetId, AZStd::pair<AZ::EntityId, AZ::Data::AssetType>>; // DEPRECATED
DependentAssets m_dependentAssets; // DEPRECATED
// An endpoint(NodeId, SlotId Pair) is represents one end of a potential connection
// The endpoint map is lookup table for all endpoints connected on the opposite end of the key value endpoint
AZStd::unordered_multimap<Endpoint, Endpoint> m_endpointMap; ///< Endpoint map built at edit time based on active connections
static bool VersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement);
};
}
@@ -0,0 +1,84 @@
/*
* 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
#include <AzCore/std/hash.h>
#include <ScriptCanvas/Core/Endpoint.h>
#include <ScriptCanvas/Core/Core.h>
#include <ScriptCanvas/Variable/VariableCore.h>
namespace ScriptCanvas
{
template<class T>
class GraphScopedIdentifier
{
public:
AZ_RTTI((GraphScopedIdentifier, "{1B01849B-57BA-4926-8DF6-252966E2BF8F}", T));
GraphScopedIdentifier() = default;
GraphScopedIdentifier(const ScriptCanvasId& scriptCanvasId, const T& identifier)
: m_scriptCanvasId(scriptCanvasId)
, m_identifier(identifier)
{
}
GraphScopedIdentifier(const GraphScopedIdentifier& other)
: m_scriptCanvasId(other.m_scriptCanvasId)
, m_identifier(other.m_identifier)
{
}
virtual ~GraphScopedIdentifier() = default;
bool operator==(const GraphScopedIdentifier& other) const
{
return m_scriptCanvasId == other.m_scriptCanvasId && m_identifier == other.m_identifier;
}
void Clear()
{
m_scriptCanvasId.SetInvalid();
m_identifier = T();
}
bool IsValid()
{
return m_scriptCanvasId.IsValid() && m_identifier.IsValid();
}
ScriptCanvasId m_scriptCanvasId;
T m_identifier;
};
typedef GraphScopedIdentifier<VariableId> GraphScopedVariableId;
typedef GraphScopedIdentifier<AZ::EntityId> GraphScopedNodeId;
typedef GraphScopedIdentifier<Endpoint> GraphScopedEndpoint;
}
namespace AZStd
{
template<class T>
struct hash<ScriptCanvas::GraphScopedIdentifier<T>>
{
size_t operator()(const ScriptCanvas::GraphScopedIdentifier<T>& key)
{
size_t seed = 0;
AZStd::hash_combine(seed, AZStd::hash<T>{}(key.m_identifier), AZStd::hash<ScriptCanvas::ScriptCanvasId>{}(key.m_scriptCanvasId));
return seed;
}
};
}
@@ -0,0 +1,193 @@
/*
* 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 <ScriptCanvas/Core/ModifiableDatumView.h>
#include <ScriptCanvas/Variable/VariableBus.h>
#include <ScriptCanvas/Variable/GraphVariable.h>
namespace ScriptCanvas
{
////////////////////////
// ModifiableDatumView
////////////////////////
ModifiableDatumView::ModifiableDatumView()
: m_datum(nullptr)
{
}
ModifiableDatumView::ModifiableDatumView(const AZ::EntityId& uniqueId, const VariableId& variableId)
: ModifiableDatumView()
{
ConfigureView(uniqueId, variableId);
}
ModifiableDatumView::~ModifiableDatumView()
{
}
bool ModifiableDatumView::IsValid() const
{
return m_datum != nullptr;
}
bool ModifiableDatumView::IsType(const ScriptCanvas::Data::Type& dataType) const
{
return m_datum ? (m_datum->GetType() == dataType) : false;
}
ScriptCanvas::Data::Type ModifiableDatumView::GetDataType() const
{
return m_datum ? m_datum->GetType() : ScriptCanvas::Data::Type::Invalid();
}
void ModifiableDatumView::SetDataType(const ScriptCanvas::Data::Type& dataType)
{
if (m_datum)
{
m_datum->SetType(dataType);
}
}
const Datum* ModifiableDatumView::GetDatum() const
{
return m_datum;
}
Datum ModifiableDatumView::CloneDatum()
{
return m_datum ? Datum((*m_datum)) : Datum();
}
void ModifiableDatumView::SetLabel(const AZStd::string& label)
{
m_datum->SetLabel(label);
}
void ModifiableDatumView::SetToDefaultValueOfType()
{
if (m_datum)
{
m_datum->SetToDefaultValueOfType();
}
}
void ModifiableDatumView::AssignToDatum(Datum&& datum)
{
if (m_datum)
{
(*m_datum) = AZStd::move(datum);
SignalModification();
}
}
void ModifiableDatumView::AssignToDatum(const Datum& datum)
{
if (m_datum)
{
ComparisonOutcome comparisonResult = (*m_datum) != datum;
if (!comparisonResult || comparisonResult.GetValue())
{
(*m_datum) = datum;
SignalModification();
}
}
}
void ModifiableDatumView::ReconfigureDatumTo(Datum&& datum)
{
if (m_datum)
{
m_datum->ReconfigureDatumTo(AZStd::move(datum));
SignalModification();
}
}
void ModifiableDatumView::HardCopyDatum(const Datum& datum)
{
if (m_datum)
{
m_datum->DeepCopyDatum(datum);
SignalModification();
}
}
void ModifiableDatumView::RelabelDatum(const AZStd::string& datumName)
{
// If it's a variable datum. We want to just leave it alone.
if (m_scopedVariableId.IsValid() || m_datum == nullptr)
{
return;
}
m_datum->SetLabel(datumName);
}
void ModifiableDatumView::SetVisibility(AZ::Crc32 visibility)
{
if (m_scopedVariableId.IsValid() || m_datum == nullptr)
{
return;
}
m_datum->SetVisibility(visibility);
}
AZ::Crc32 ModifiableDatumView::GetVisibility() const
{
return m_datum ? m_datum->GetVisibility() : AZ::Crc32();
}
Datum* ModifiableDatumView::ModifyDatum()
{
return m_datum;
}
void ModifiableDatumView::ConfigureView(GraphVariable& graphVariable)
{
SignalModification();
m_datum = &graphVariable.m_datum;
m_scopedVariableId = graphVariable.GetGraphScopedId();
}
void ModifiableDatumView::ConfigureView(Datum& datum)
{
SignalModification();
m_datum = &datum;
m_scopedVariableId.Clear();
}
void ModifiableDatumView::ConfigureView(const ScriptCanvasId& scriptCanvasId, const VariableId& variableId)
{
GraphVariable* variable = nullptr;
VariableRequestBus::EventResult(variable, GraphScopedVariableId(scriptCanvasId, variableId), &VariableRequests::GetVariable);
if (variable)
{
ConfigureView((*variable));
}
}
void ModifiableDatumView::SignalModification()
{
if (m_scopedVariableId.IsValid())
{
VariableNotificationBus::Event(m_scopedVariableId, &VariableNotifications::OnVariableValueChanged);
}
}
}
@@ -0,0 +1,108 @@
/*
* 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
#include <ScriptCanvas/Core/Datum.h>
#include <ScriptCanvas/Variable/VariableCore.h>
#include <ScriptCanvas/Core/GraphScopedTypes.h>
namespace ScriptCanvas
{
class GraphVariable;
class Node;
// Class that will return the Datum* pointed to by a paritcular variable.
// Will handle signalling out changes.
//
// Should only be held in local functions and not stored for long-term use.
class ModifiableDatumView
{
private:
// Ensure object cannot be copied.
ModifiableDatumView(const ModifiableDatumView&) = delete;
ModifiableDatumView& operator=(const ModifiableDatumView&) = delete;
friend class Node;
friend class GraphVariable;
friend class PureData;
public:
AZ_CLASS_ALLOCATOR(ModifiableDatumView, AZ::SystemAllocator, 0);
ModifiableDatumView();
ModifiableDatumView(const AZ::EntityId& uniqueId, const VariableId& variableId);
~ModifiableDatumView();
bool IsValid() const;
bool IsType(const ScriptCanvas::Data::Type& dataType) const;
ScriptCanvas::Data::Type GetDataType() const;
void SetDataType(const ScriptCanvas::Data::Type& dataType);
const Datum* GetDatum() const;
Datum CloneDatum();
void SetLabel(const AZStd::string& label);
void SetToDefaultValueOfType();
void AssignToDatum(Datum&& datum);
void AssignToDatum(const Datum& datum);
void ReconfigureDatumTo(Datum&& datum);
void HardCopyDatum(const Datum& datum);
template<typename DataType>
void SetAs(const DataType& arg)
{
(*m_datum->ModAs<DataType>()) = arg;
SignalModification();
}
template<typename DataType>
void SetAs(DataType&& arg)
{
(*m_datum->ModAs<AZStd::remove_cvref_t<DataType>>()) = AZStd::forward<DataType>(arg);
SignalModification();
}
template<typename DataType>
const DataType* GetAs() const
{
return m_datum ? m_datum->GetAs<DataType>() : nullptr;
}
void RelabelDatum(const AZStd::string& datumName);
void SetVisibility(AZ::Crc32 visibility);
AZ::Crc32 GetVisibility() const;
protected:
Datum* ModifyDatum();
void ConfigureView(GraphVariable& graphVariable);
void ConfigureView(Datum& datum);
void ConfigureView(const ScriptCanvasId& uniqueId, const VariableId& variableId);
void SignalModification();
private:
Datum* m_datum;
bool m_isDirty = false;
GraphScopedVariableId m_scopedVariableId;
};
}
@@ -0,0 +1,124 @@
/*
* 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
#include <AzCore/base.h>
#include <AzCore/RTTI/TypeInfo.h>
#include <AzCore/std/string/string.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace ScriptCanvas
{
class ReflectContext;
template<typename t_Id>
class NamedId : public t_Id
{
public:
using ThisType = NamedId<t_Id>;
AZ_CLASS_ALLOCATOR(NamedId<t_Id>, AZ::SystemAllocator, 0);
AZ_RTTI(((NamedId<t_Id>) , "{7DFA6B31-B283-48BE-9D6F-260D8994C593}", t_Id), t_Id);
static void Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<ThisType, t_Id>()
->Version(0)
->Field("name", &ThisType::m_name)
;
}
}
AZStd::string m_name;
NamedId() = default;
virtual ~NamedId() = default;
NamedId(const NamedId&) = default;
explicit NamedId(const t_Id& id)
: t_Id(id)
, m_name("")
{}
NamedId(const t_Id& id, AZStd::string_view name)
: t_Id(id)
, m_name(name)
{}
AZStd::string ToString() const
{
return AZStd::string::format("%s [%s]", m_name.data(), t_Id::ToString().data());
}
bool operator==(const NamedId& rhs) const
{
return t_Id::operator==(rhs);
}
bool operator==(const t_Id& rhs) const
{
return t_Id::operator==(rhs);
}
bool operator!=(const NamedId& rhs) const
{
return t_Id::operator!=(rhs);
}
bool operator!=(const t_Id& rhs) const
{
return t_Id::operator!=(rhs);
}
bool operator<(const NamedId& rhs) const
{
return t_Id::operator<(rhs);
}
bool operator<(const t_Id& rhs) const
{
return t_Id::operator<(rhs);
}
bool operator>(const NamedId& rhs) const
{
return t_Id::operator>(rhs);
}
bool operator>(const t_Id& rhs) const
{
return t_Id::operator>(rhs);
}
};
} // namespace AZ
namespace AZStd
{
template<typename t_Id>
struct hash<ScriptCanvas::NamedId<t_Id>>
{
typedef ScriptCanvas::NamedId<t_Id> argument_type;
typedef AZStd::size_t result_type;
AZ_FORCE_INLINE size_t operator()(const argument_type& namedId) const
{
return AZStd::hash<t_Id>()(namedId);
}
};
} // namespace AZStd
@@ -0,0 +1,138 @@
/*
* 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
#include <Data/Data.h>
#include <ScriptCanvas/Core/Node.h>
#include <ScriptCanvas/Core/PureData.h>
#include <AzCore/std/typetraits/function_traits.h>
namespace ScriptCanvas
{
namespace Nodes
{
template<typename t_Node, typename t_Datum>
class NativeDatumNode
: public PureData
{
public:
using t_ThisType = NativeDatumNode<t_Node, t_Datum>;
AZ_RTTI(((NativeDatumNode<t_Node, t_Datum>), "{B7D8D8D6-B2F1-481A-A712-B07D1C19555F}", t_Node, t_Datum), PureData, AZ::Component);
AZ_COMPONENT_INTRUSIVE_DESCRIPTOR_TYPE(NativeDatumNode);
AZ_COMPONENT_BASE(NativeDatumNode, PureData);
static void Reflect(AZ::ReflectContext* reflection)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
{
serializeContext->Class<t_ThisType, PureData>()
->Version(0)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<t_ThisType>("NativeDatumNode", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
;
}
}
}
~NativeDatumNode() override = default;
protected:
virtual void ConfigureSetters()
{
Data::SetterContainer setterWrappers = Data::ExplodeToSetters(Data::FromAZType(Data::Traits<t_Datum>::GetAZType()));
for (const auto& setterWrapperPair : setterWrappers)
{
SlotId setterSlotId;
const Data::SetterWrapper& setterWrapper = setterWrapperPair.second;
const AZStd::string argName = AZStd::string::format("%s: %s", Data::GetName(setterWrapper.m_propertyType).data(), setterWrapper.m_propertyName.data());
AZStd::string_view argumentTooltip;
// Add the slot if it doesn't exist
setterSlotId = FindSlotIdForDescriptor(argName, SlotDescriptors::DataIn());
if (!setterSlotId.IsValid())
{
DataSlotConfiguration slotConfiguration;
slotConfiguration.m_name = argName;
slotConfiguration.m_toolTip = argumentTooltip;
slotConfiguration.SetType(setterWrapper.m_propertyType);
slotConfiguration.SetConnectionType(ConnectionType::Input);
setterSlotId = AddSlot(slotConfiguration);
}
if (setterSlotId.IsValid())
{
m_propertyAccount.m_getterSetterIdPairs[setterWrapperPair.first].second = setterSlotId;
m_propertyAccount.m_settersByInputSlot.emplace(setterSlotId, setterWrapperPair.second);
}
}
}
virtual void ConfigureGetters()
{
Data::GetterContainer getterWrappers = Data::ExplodeToGetters(Data::FromAZType(Data::Traits<t_Datum>::GetAZType()));
for (const auto& getterWrapperPair : getterWrappers)
{
SlotId getterSlotId;
const Data::GetterWrapper& getterWrapper = getterWrapperPair.second;
const AZStd::string resultSlotName(AZStd::string::format("%s: %s", getterWrapper.m_propertyName.data(), Data::GetName(getterWrapper.m_propertyType).data()));
// Add the slot if it doesn't exist
getterSlotId = FindSlotIdForDescriptor(resultSlotName, SlotDescriptors::DataOut());
if (!getterSlotId.IsValid())
{
DataSlotConfiguration slotConfiguration;
slotConfiguration.m_name = resultSlotName;
slotConfiguration.SetType(getterWrapper.m_propertyType);
slotConfiguration.SetConnectionType(ConnectionType::Output);
getterSlotId = AddSlot(slotConfiguration);
}
if (getterSlotId.IsValid())
{
m_propertyAccount.m_getterSetterIdPairs[getterWrapperPair.first].first = getterSlotId;
m_propertyAccount.m_gettersByInputSlot.emplace(getterSlotId, getterWrapperPair.second);
}
}
}
virtual void ConfigureProperties()
{
if (IsConfigured())
{
return;
}
ConfigureGetters();
ConfigureSetters();
m_configured = true;
}
void OnInit() override
{
AddInputAndOutputTypeSlot(Data::FromAZType<t_Datum>());
ConfigureProperties();
}
};
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,143 @@
/*
* 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
#include "Core.h"
#include <AzCore/Outcome/Outcome.h>
#include <AzCore/std/string/string_view.h>
#include <AzCore/EBus/EBus.h>
#include <ScriptCanvas/Data/Data.h>
#include <ScriptCanvas/Core/SlotConfigurations.h>
namespace ScriptCanvas
{
struct VariableId;
class Datum;
class Slot;
class ModifiableDatumView;
class NodeRequests : public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = ID;
virtual Slot* GetSlot(const SlotId& slotId) const = 0;
virtual size_t GetSlotIndex(const SlotId& slotId) const = 0;
//! Gets all of the slots on the node.
//! Name is funky to avoid a mismatch with typing with another function
//! that returns a better version of this information that cannot be used with
//! EBuses because of references.
virtual AZStd::vector<const Slot*> GetAllSlots() const = 0;
//! Retrieves a slot id that matches the supplied name
//! There can be multiple slots with the same name on a node
//! Therefore this should only be used when a slot's name is unique within the node
virtual SlotId GetSlotId(AZStd::string_view slotName) const = 0;
virtual SlotId FindSlotIdForDescriptor(AZStd::string_view slotName, const SlotDescriptor& descriptor) const = 0;
//! Retrieves a slot id that matches the supplied name and the supplied slot type
virtual SlotId GetSlotIdByType(AZStd::string_view slotName, CombinedSlotType slotType) const
{
return FindSlotIdForDescriptor(slotName, SlotDescriptor(slotType));
}
//! Retrieves all slot ids for slots with the specific name
virtual AZStd::vector<SlotId> GetSlotIds(AZStd::string_view slotName) const = 0;
virtual const ScriptCanvasId& GetOwningScriptCanvasId() const = 0;
//! Get the Datum for the specified slot.
virtual const Datum* FindDatum(const SlotId& slotId) const = 0;
const Datum* GetInput(const SlotId& slotId) const
{
AZ_Warning("ScriptCanvas", false, "Using Deprecated GetInput method call. Please switch to FindDatum call instead, this method will be removed in a future update.");
return FindDatum(slotId);
}
virtual void FindModifiableDatumView(const SlotId& slotId, ModifiableDatumView& datumView) = 0;
//! Determines whether the slot on this node with the specified slot id can accept values of the specified type
virtual bool SlotAcceptsType(const SlotId&, const Data::Type&) const = 0;
//! Gets the input for the given SlotId
virtual Data::Type GetSlotDataType(const SlotId& slotId) const = 0;
// Retrieves the variable id which is represents the current variable associated with the specified slot
virtual VariableId GetSlotVariableId(const SlotId& slotId) const = 0;
// Sets the variable id parameter as the current variable for the specified slot
virtual void SetSlotVariableId(const SlotId& slotId, const VariableId& variableId) = 0;
// Reset the variable id value to the original variable id that was associated with the slot
// when the slot was created by a call to AddInputDatumSlot().
// The reset variable Id is not associated Variable Manager and is owned by this node
virtual void ClearSlotVariableId(const SlotId& slotId) = 0;
virtual int FindSlotIndex(const SlotId& slotId) const = 0;
virtual bool IsOnPureDataThread(const SlotId& slotId) const = 0;
virtual AZ::Outcome<void, AZStd::string> IsValidTypeForGroup(const AZ::Crc32& dynamicGroup, const Data::Type& dataType) const = 0;
virtual void SignalBatchedConnectionManipulationBegin() = 0;
virtual void SignalBatchedConnectionManipulationEnd() = 0;
virtual void SetNodeEnabled(bool enabled) = 0;
virtual bool IsNodeEnabled() const = 0;
virtual bool RemoveVariableReferences(const AZStd::unordered_set< ScriptCanvas::VariableId >& variableIds) = 0;
};
using NodeRequestBus = AZ::EBus<NodeRequests>;
class LogNotifications : public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = ScriptCanvasId;
virtual void LogMessage([[maybe_unused]] const AZStd::string& log) {}
};
using LogNotificationBus = AZ::EBus<LogNotifications>;
class NodeNotifications
: public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = AZ::EntityId;
virtual void OnInputChanged(const SlotId& /*slotId*/) {}
//! Events signaled when a slot is added or removed from a node
virtual void OnSlotAdded(const SlotId& /*slotId*/) {}
virtual void OnSlotRemoved(const SlotId& /*slotId*/) {}
virtual void OnSlotRenamed(const SlotId& /*slotId*/, AZStd::string_view /*newName*/) {}
virtual void OnSlotDisplayTypeChanged(const SlotId& /*slotId*/, const ScriptCanvas::Data::Type& /*slotType*/) {}
virtual void OnSlotActiveVariableChanged(const SlotId& /*slotId*/, [[maybe_unused]] const VariableId& oldVariableId, [[maybe_unused]] const VariableId& newVariableId) {}
virtual void OnSlotsReordered() {}
virtual void OnNodeDisabled() {};
virtual void OnNodeEnabled() {};
};
using NodeNotificationsBus = AZ::EBus<NodeNotifications>;
}
@@ -0,0 +1,340 @@
/*
* 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
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/RTTI/TypeInfo.h>
#include <AzCore/std/tuple.h>
#include <AzCore/std/typetraits/add_pointer.h>
#include <AzCore/std/typetraits/function_traits.h>
#include <ScriptCanvas/Libraries/Libraries.h>
#include "Node.h"
#include "Attributes.h"
/**
* NodeFunctionGeneric.h
*
* This file makes it really easy to take a single function and make into a ScriptCanvas node
* with all of the necessary plumbing, by using a macro, and adding the result to a node registry.
*
* Use SCRIPT_CANVAS_GENERIC_FUNCTION_MULTI_RESULTS_NODE for a function of any arity that returns [0, N]
* arguments, wrapped in a tuple.
*
* The macros will turn the function name into a ScriptCanvas node with name of the function
* with "Node" appended to it.
*
* \note As much as possible, it best to wrap functions that use 'native' ScriptCanvas types,
* and to pass them in/out by value.
* You will need to add the nodes to the registry like any other node, and get a component description
* from it, in order to have it show up in the editor, etc.
*
* It is preferable to use this method for any node that provides ScriptCanvas-only functionality.
* If you are creating a node that represents functionality that would be useful in Lua, or any other
* client of BehaviorContext, it may be better to expose your functionality to BehaviorContext, unless
* performance in ScriptCanvas is an issue. This method will almost certainly provide faster run-time
* performance than a node that calls into BehaviorContext.
*
* A good faith effort to support reference return types has been made. Pointers and references, even in
* tuples, are supported. However, if your input or return values is T** or T*&, it won't work, and there
* are no plans to support them. If your tuple return value is made up of references remember to return it with
* std::forward_as_tuple, and not std::make_tuple.
*
* \see MathGenerics.h and Math.cpp for example usage of the macros and generic registrar defined below.
*
*/
// this defines helps provide type safe static asserts in the results of the macros below
#define SCRIPT_CANVAS_FUNCTION_VAR_ARGS(...) (AZStd::tuple_size<decltype(AZStd::make_tuple(__VA_ARGS__))>::value)
namespace ScriptCanvas
{
namespace Internal
{
template<class T, typename = AZStd::void_t<>>
struct extended_tuple_size : AZStd::integral_constant<size_t, 1> {};
template<class T>
struct extended_tuple_size<T, AZStd::enable_if_t<IsTupleLike<T>::value>> : AZStd::tuple_size<T>{};
template<>
struct extended_tuple_size<void, AZStd::void_t<>>: AZStd::integral_constant<size_t, 0> {};
}
}
#define SCRIPT_CANVAS_GENERIC_FUNCTION_MULTI_RESULTS_NODE_WITH_DEFAULTS(NODE_NAME, DEFAULT_FUNC, CATEGORY, UUID, ISDEPRECATED, DESCRIPTION, ...)\
struct NODE_NAME##Traits\
{\
AZ_TYPE_INFO(NODE_NAME##Traits, UUID);\
using FunctionTraits = AZStd::function_traits< decltype(&NODE_NAME) >;\
using ResultType = FunctionTraits::result_type;\
static const size_t s_numArgs = FunctionTraits::arity;\
static const size_t s_numNames = SCRIPT_CANVAS_FUNCTION_VAR_ARGS(__VA_ARGS__);\
static const size_t s_argsSlotIndicesStart = 2;\
static const size_t s_resultsSlotIndicesStart = s_argsSlotIndicesStart + s_numArgs;\
static const size_t s_numResults = ScriptCanvas::Internal::extended_tuple_size<ResultType>::value;\
\
static const char* GetArgName(size_t i)\
{\
return GetName(i).data();\
}\
\
static const char* GetResultName(size_t i)\
{\
AZStd::string_view result = GetName(i + s_numArgs);\
return !result.empty() ? result.data() : "Result";\
}\
\
static const char* GetCategory() { if (ISDEPRECATED) return AZ_STRINGIZE(CATEGORY /Deprecated); else return CATEGORY; };\
static const char* GetDescription() { return DESCRIPTION; };\
static const char* GetNodeName() { return #NODE_NAME; };\
static bool IsDeprecated() { return ISDEPRECATED; };\
\
private:\
static AZStd::string_view GetName(size_t i)\
{\
static_assert(s_numArgs <= s_numNames, "Number of arguments is greater than number of names in " #NODE_NAME );\
/*static_assert(s_numResults <= s_numNames, "Number of results is greater than number of names in " #NODE_NAME );*/\
/*static_assert((s_numResults + s_numArgs) == s_numNames, "Argument name count + result name count != name count in " #NODE_NAME );*/\
static const AZStd::array<AZStd::string_view, s_numNames> s_names = {{ __VA_ARGS__ }};\
return i < s_names.size() ? s_names[i] : "";\
}\
};\
using NODE_NAME##Node = ScriptCanvas::NodeFunctionGenericMultiReturn<AZStd::add_pointer_t<decltype(NODE_NAME)>, NODE_NAME##Traits, &NODE_NAME, AZStd::add_pointer_t<decltype(DEFAULT_FUNC)>, &DEFAULT_FUNC>;
#define SCRIPT_CANVAS_GENERIC_FUNCTION_MULTI_RESULTS_NODE(NODE_NAME, CATEGORY, UUID, DESCRIPTION, ...)\
SCRIPT_CANVAS_GENERIC_FUNCTION_MULTI_RESULTS_NODE_WITH_DEFAULTS(NODE_NAME, ScriptCanvas::NoDefaultArguments, CATEGORY, UUID, false, DESCRIPTION, __VA_ARGS__)
#define SCRIPT_CANVAS_GENERIC_FUNCTION_MULTI_RESULTS_NODE_DEPRECATED(NODE_NAME, CATEGORY, UUID, DESCRIPTION, ...)\
SCRIPT_CANVAS_GENERIC_FUNCTION_MULTI_RESULTS_NODE_WITH_DEFAULTS(NODE_NAME, ScriptCanvas::NoDefaultArguments, CATEGORY, UUID, true, DESCRIPTION, __VA_ARGS__)
#define SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(NODE_NAME, DEFAULT_FUNC, CATEGORY, UUID, DESCRIPTION, ...)\
SCRIPT_CANVAS_GENERIC_FUNCTION_MULTI_RESULTS_NODE_WITH_DEFAULTS(NODE_NAME, DEFAULT_FUNC, CATEGORY, UUID, false, DESCRIPTION, __VA_ARGS__)
#define SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS_DEPRECATED(NODE_NAME, DEFAULT_FUNC, CATEGORY, UUID, DESCRIPTION, ...)\
SCRIPT_CANVAS_GENERIC_FUNCTION_MULTI_RESULTS_NODE_WITH_DEFAULTS(NODE_NAME, DEFAULT_FUNC, CATEGORY, UUID, true, DESCRIPTION, __VA_ARGS__)
#define SCRIPT_CANVAS_GENERIC_FUNCTION_NODE(NODE_NAME, CATEGORY, UUID, DESCRIPTION, ...)\
SCRIPT_CANVAS_GENERIC_FUNCTION_MULTI_RESULTS_NODE_WITH_DEFAULTS(NODE_NAME, ScriptCanvas::NoDefaultArguments, CATEGORY, UUID, false, DESCRIPTION, __VA_ARGS__)
#define SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_DEPRECATED(NODE_NAME, CATEGORY, UUID, DESCRIPTION, ...)\
SCRIPT_CANVAS_GENERIC_FUNCTION_MULTI_RESULTS_NODE_WITH_DEFAULTS(NODE_NAME, ScriptCanvas::NoDefaultArguments, CATEGORY, UUID, true, DESCRIPTION, __VA_ARGS__)
namespace ScriptCanvas
{
template<size_t... inputDatumIndices>
struct SetDefaultValuesByIndex
{
template<typename... t_Args>
AZ_INLINE static void _(Node& node, t_Args&&... args)
{
Help(node, AZStd::make_index_sequence<sizeof...(t_Args)>(), AZStd::forward<t_Args>(args)...);
}
private:
template<AZStd::size_t... Is, typename... t_Args>
AZ_INLINE static void Help(Node& node, AZStd::index_sequence<Is...>, t_Args&&... args)
{
static int indices[] = { inputDatumIndices... };
static_assert(sizeof...(Is) == AZ_ARRAY_SIZE(indices), "size of default values doesn't match input datum indices for them");
std::initializer_list<int> { (MoreHelp(node, indices[Is], AZStd::forward<t_Args>(args)), 0)... };
}
template<typename ArgType>
AZ_INLINE static void MoreHelp(Node& node, size_t datumIndex, ArgType&& arg)
{
ModifiableDatumView datumView;
node.FindModifiableDatumViewByIndex(datumIndex, datumView);
datumView.template SetAs<AZStd::remove_cvref_t<ArgType>>(AZStd::forward<ArgType>(arg));
}
};
// a no-op for generic function nodes that have no overrides for default input
AZ_INLINE void NoDefaultArguments(Node&) {}
template<typename t_Func, typename t_Traits, t_Func function, typename t_DefaultFunc, t_DefaultFunc defaultsFunction>
class NodeFunctionGeneric
: public Node
{
public:
// This class has been deprecated for NodeFunctionGenericMultiReturn
NodeFunctionGeneric() = delete;
AZ_RTTI(((NodeFunctionGeneric<t_Func, t_Traits, function, t_DefaultFunc, defaultsFunction>), "{19E4AABE-1730-402C-A020-FC1006BC7F7B}", t_Func, t_Traits, t_DefaultFunc), Node);
AZ_COMPONENT_INTRUSIVE_DESCRIPTOR_TYPE(NodeFunctionGeneric);
AZ_COMPONENT_BASE(NodeFunctionGeneric, Node);
};
template<typename t_Func, typename t_Traits, t_Func function, typename t_DefaultFunc, t_DefaultFunc defaultsFunction>
class NodeFunctionGenericMultiReturn
: public Node
{
public:
AZ_RTTI(((NodeFunctionGenericMultiReturn<t_Func, t_Traits, function>), "{DC5B1799-6C5B-4190-8D90-EF0C2D1BCE4E}", t_Func, t_Traits), Node);
AZ_COMPONENT_INTRUSIVE_DESCRIPTOR_TYPE(NodeFunctionGenericMultiReturn);
AZ_COMPONENT_BASE(NodeFunctionGenericMultiReturn, Node);
static void Reflect(AZ::ReflectContext* reflectContext)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext))
{
serializeContext->Class<NodeFunctionGenericMultiReturn, Node>()
->Version(1, &VersionConverter)
->Attribute(AZ::Script::Attributes::Deprecated, t_Traits::IsDeprecated())
->Field("Initialized", &NodeFunctionGenericMultiReturn::m_initialized)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<NodeFunctionGenericMultiReturn>(t_Traits::GetNodeName(), t_Traits::GetDescription())
->ClassElement(AZ::Edit::ClassElements::EditorData, t_Traits::GetDescription())
->Attribute(AZ::Script::Attributes::Deprecated, t_Traits::IsDeprecated())
->Attribute(ScriptCanvas::Attributes::Node::TitlePaletteOverride, t_Traits::IsDeprecated() ? "DeprecatedNodeTitlePalette" : "")
->Attribute(AZ::Edit::Attributes::Category, t_Traits::GetCategory())
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
;
}
// NodeFunctionGeneric class has been deprecated in terms of the this class
serializeContext->ClassDeprecate("NodeFunctionGeneric", azrtti_typeid<NodeFunctionGeneric<t_Func, t_Traits, function, t_DefaultFunc, defaultsFunction>>(), &ConvertOldNodeGeneric);
// Need to calculate the Typeid for the old NodeFunctionGeneric class as if it contains no templated types which are pointers
AZ::Uuid genericTypeIdPointerRemoved = AZ::Uuid{ "{19E4AABE-1730-402C-A020-FC1006BC7F7B}" } + AZ::Internal::AggregateTypes<t_Func, t_Traits, t_DefaultFunc>::template Uuid<AZ::PointerRemovedTypeIdTag>();
serializeContext->ClassDeprecate("NodeFunctionGenericTemplate", genericTypeIdPointerRemoved, &ConvertOldNodeGeneric);
// NodeFunctionGenericMultiReturn class used to use the same typeid for pointer and not-pointer types for the function parameters
// i.e, void Func(AZ::Entity*) and void Func2(AZ::Entity&) are the same typeid
AZ::Uuid genericMultiReturnV1TypeId = AZ::Uuid{ "{DC5B1799-6C5B-4190-8D90-EF0C2D1BCE4E}" } + AZ::Internal::AggregateTypes<t_Func, t_Traits>::template Uuid<AZ::PointerRemovedTypeIdTag>();
serializeContext->ClassDeprecate("NodeFunctionGenericMultiReturnV1", genericMultiReturnV1TypeId, &ConvertOldNodeGeneric);
}
}
protected:
template<typename ArgType, size_t Index>
void CreateDataSlot(const ConnectionType& connectionType)
{
DataSlotConfiguration slotConfiguration;
slotConfiguration.m_name = AZStd::string::format("%s: %s", Data::Traits<ArgType>::GetName().data(), t_Traits::GetArgName(Index));
slotConfiguration.ConfigureDatum(AZStd::move(Datum(Data::FromAZType(Data::Traits<ArgType>::GetAZType()), Datum::eOriginality::Copy)));
slotConfiguration.SetConnectionType(connectionType);
AddSlot(slotConfiguration);
}
template<typename... t_Args, AZStd::size_t... Is>
void AddInputDatumSlotHelper(AZStd::Internal::pack_traits_arg_sequence<t_Args...>, AZStd::index_sequence<Is...>)
{
static_assert(sizeof...(t_Args) == sizeof...(Is), "Argument size mismatch in NodeFunctionGenericMultiReturn");
static_assert(sizeof...(t_Args) == t_Traits::s_numArgs, "Number of arguments does not match number of argument names in NodeFunctionGenericMultiReturn");
SCRIPT_CANVAS_CALL_ON_INDEX_SEQUENCE(
(CreateDataSlot<t_Args, Is>(ConnectionType::Input))
);
}
void ConfigureSlots() override
{
{
ExecutionSlotConfiguration slotConfiguration("In", ConnectionType::Input);
AddSlot(slotConfiguration);
}
{
ExecutionSlotConfiguration slotConfiguration("Out", ConnectionType::Output);
AddSlot(slotConfiguration);
}
AddInputDatumSlotHelper(typename AZStd::function_traits<t_Func>::arg_sequence{}, AZStd::make_index_sequence<AZStd::function_traits<t_Func>::arity>{});
if (!m_initialized)
{
m_initialized = true;
defaultsFunction(*this);
}
MultipleOutputInvoker<t_Func, function, t_Traits>::Add(*this);
}
void OnInputSignal([[maybe_unused]] const SlotId& slotId) override
{
MultipleOutputInvoker<t_Func, function, t_Traits>::Call(*this);
SignalOutput(GetSlotId("Out"));
}
static bool VersionConverter(AZ::SerializeContext& serializeContext, AZ::SerializeContext::DataElementNode& rootElement);
static bool ConvertOldNodeGeneric(AZ::SerializeContext& serializeContext, AZ::SerializeContext::DataElementNode& rootElement);
private:
bool m_initialized = false;
}; // class NodeFunctionGenericMultiReturn
template<typename... t_Node>
class RegistrarGeneric
{
public:
static void AddDescriptors(AZStd::vector<AZ::ComponentDescriptor*>& descriptors)
{
SCRIPT_CANVAS_CALL_ON_INDEX_SEQUENCE(descriptors.push_back(t_Node::CreateDescriptor()));
}
template<typename t_NodeGroup>
static void AddToRegistry(NodeRegistry& nodeRegistry)
{
auto& nodes = nodeRegistry.m_nodeMap[azrtti_typeid<t_NodeGroup>()];
SCRIPT_CANVAS_CALL_ON_INDEX_SEQUENCE(nodes.push_back({ azrtti_typeid<t_Node>(), AZ::AzTypeInfo<t_Node>::Name() }));
}
}; // class RegistrarGeneric
template<typename t_Func, typename t_Traits, t_Func function, typename t_DefaultFunc, t_DefaultFunc defaultsFunction>
bool NodeFunctionGenericMultiReturn<t_Func, t_Traits, function, t_DefaultFunc, defaultsFunction>::ConvertOldNodeGeneric(AZ::SerializeContext& serializeContext, AZ::SerializeContext::DataElementNode& rootElement)
{
int nodeElementIndex = rootElement.FindElement(AZ_CRC("BaseClass1", 0xd4925735));
if (nodeElementIndex == -1)
{
AZ_Error("Script Canvas", false, "Unable to find base class node element on deprecated class %s", rootElement.GetNameString());
return false;
}
// The DataElementNode is being copied purposefully in this statement to clone the data
AZ::SerializeContext::DataElementNode baseNodeElement = rootElement.GetSubElement(nodeElementIndex);
if (!rootElement.Convert(serializeContext, azrtti_typeid<NodeFunctionGenericMultiReturn>()))
{
AZ_Error("Script Canvas", false, "Unable to convert deprecated class %s to class %s", rootElement.GetNameString(), RTTI_TypeName());
return false;
}
if (rootElement.AddElement(baseNodeElement) == -1)
{
AZ_Error("Script Canvas", false, "Unable to add base class node element to %s", RTTI_TypeName());
return false;
}
return true;
}
template<typename t_Func, typename t_Traits, t_Func function, typename t_DefaultFunc, t_DefaultFunc defaultsFunction>
bool NodeFunctionGenericMultiReturn<t_Func, t_Traits, function, t_DefaultFunc, defaultsFunction>::VersionConverter(AZ::SerializeContext& serializeContext, AZ::SerializeContext::DataElementNode& rootElement)
{
if (rootElement.GetVersion() < 1)
{
rootElement.AddElementWithData(serializeContext, "Initialized", true);
}
return true;
}
}
@@ -0,0 +1,47 @@
/*
* 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
#include <AzCore/EBus/EBus.h>
#include <AzCore/std/string/string.h>
#include <ScriptCanvas/Core/GraphScopedTypes.h>
namespace ScriptCanvas
{
class NodelingRequests : public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = GraphScopedNodeId;
virtual AZ::EntityId GetNodeId() const = 0;
virtual GraphScopedNodeId GetGraphScopedNodeId() const = 0;
virtual const AZStd::string& GetDisplayName() const = 0;
virtual void SetDisplayName(const AZStd::string& displayName) = 0;
};
using NodelingRequestBus = AZ::EBus<NodelingRequests>;
class NodelingNotifications : public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = GraphScopedNodeId;
virtual void OnNameChanged(const AZStd::string& newName) = 0;
};
using NodelingNotificationBus = AZ::EBus<NodelingNotifications>;
}
@@ -0,0 +1,235 @@
/*
* 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 "PureData.h"
namespace ScriptCanvas
{
const char* PureData::k_getThis("Get");
const char* PureData::k_setThis("Set");
PureData::~PureData()
{
}
const AZStd::unordered_map<AZStd::string, AZStd::pair<SlotId, SlotId>>& PureData::GetPropertyNameSlotMap() const
{
return m_propertyAccount.m_getterSetterIdPairs;
}
void PureData::AddInputAndOutputTypeSlot(const Data::Type& type, const void* source)
{
{
DataSlotConfiguration slotConfiguration;
slotConfiguration.m_name = k_setThis;
slotConfiguration.SetConnectionType(ConnectionType::Input);
slotConfiguration.ConfigureDatum(AZStd::move(Datum(type, Datum::eOriginality::Original, source, AZ::Uuid::CreateNull())));
AddSlot(slotConfiguration);
}
{
DataSlotConfiguration slotConfiguration;
slotConfiguration.m_name = k_getThis;
slotConfiguration.SetConnectionType(ConnectionType::Output);
slotConfiguration.SetType(type);
AddSlot(slotConfiguration);
}
}
void PureData::AddInputTypeAndOutputTypeSlot(const Data::Type& type)
{
{
DataSlotConfiguration slotConfiguration;
slotConfiguration.m_name = k_setThis;
slotConfiguration.SetConnectionType(ConnectionType::Input);
slotConfiguration.SetType(type);
AddSlot(slotConfiguration);
}
{
DataSlotConfiguration slotConfiguration;
slotConfiguration.m_name = k_getThis;
slotConfiguration.SetConnectionType(ConnectionType::Output);
slotConfiguration.SetType(type);
AddSlot(slotConfiguration);
}
}
void PureData::OnActivate()
{
PushThis();
for (const auto& propertySlotIdsPair : m_propertyAccount.m_getterSetterIdPairs)
{
const SlotId& getterSlotId = propertySlotIdsPair.second.first;
CallGetter(getterSlotId);
}
}
void PureData::OnInputChanged(const Datum& input, [[maybe_unused]] const SlotId& id)
{
if (IsActivated())
{
OnOutputChanged(input);
}
}
AZStd::string_view PureData::GetInputDataName() const
{
return k_setThis;
}
AZStd::string_view PureData::GetOutputDataName() const
{
return k_getThis;
}
void PureData::CallGetter(const SlotId& getterSlotId)
{
auto getterFuncIt = m_propertyAccount.m_gettersByInputSlot.find(getterSlotId);
Slot* getterSlot = GetSlot(getterSlotId);
if (getterSlot && getterFuncIt != m_propertyAccount.m_gettersByInputSlot.end())
{
AZStd::vector<AZStd::pair<Node*, const SlotId>> outputNodes(ModConnectedNodes(*getterSlot));
if (!outputNodes.empty())
{
auto getterOutcome = getterFuncIt->second.m_getterFunction((*FindDatum(GetSlotId(k_setThis))));
if (!getterOutcome)
{
SCRIPTCANVAS_REPORT_ERROR((*this), getterOutcome.GetError().data());
return;
}
for (auto& nodePtrSlot : outputNodes)
{
if (nodePtrSlot.first)
{
Node::SetInput(*nodePtrSlot.first, nodePtrSlot.second, getterOutcome.GetValue());
}
}
}
}
}
void PureData::SetInput(const Datum& input, const SlotId& id)
{
if (id == FindSlotIdForDescriptor(GetInputDataName(), SlotDescriptors::DataIn()))
{
// push this value, as usual
Node::SetInput(input, id);
// now, call every getter, as every property has (presumably) been changed
for (const auto& propertyNameSlotIdsPair : m_propertyAccount.m_getterSetterIdPairs)
{
const SlotId& getterSlotId = propertyNameSlotIdsPair.second.first;
CallGetter(getterSlotId);
}
}
else
{
SetProperty(input, id);
}
}
void PureData::SetInput(Datum&& input, const SlotId& id)
{
if (id == FindSlotIdForDescriptor(GetInputDataName(), SlotDescriptors::DataIn()))
{
// push this value, as usual
Node::SetInput(AZStd::move(input), id);
if (IsActivated())
{
// now, call every getter, as every property has (presumably) been changed
for (const auto& propertyNameSlotIdsPair : m_propertyAccount.m_getterSetterIdPairs)
{
const SlotId& getterSlotId = propertyNameSlotIdsPair.second.first;
CallGetter(getterSlotId);
}
}
}
else
{
SetProperty(AZStd::move(input), id);
}
}
void PureData::SetProperty(const Datum& input, const SlotId& setterId)
{
auto methodBySlotIter = m_propertyAccount.m_settersByInputSlot.find(setterId);
if (methodBySlotIter == m_propertyAccount.m_settersByInputSlot.end())
{
AZ_Error("Script Canvas", false, "BehaviorContextObject SlotId %s did not route to a setter", setterId.m_id.ToString<AZStd::string>().data());
return;
}
if (!methodBySlotIter->second.m_setterFunction)
{
AZ_Error("Script Canvas", false, "BehaviorContextObject setter is not invocable for SlotId %s is nullptr", setterId.m_id.ToString<AZStd::string>().data());
return;
}
ModifiableDatumView datumView;
FindModifiableDatumView(GetSlotId(k_setThis), datumView);
Datum* datum = datumView.ModifyDatum();
auto setterOutcome = methodBySlotIter->second.m_setterFunction((*datum), input);
if (!setterOutcome)
{
SCRIPTCANVAS_REPORT_ERROR((*this), setterOutcome.TakeError().data());
return;
}
datumView.SignalModification();
PushThis();
auto getterSetterIt = m_propertyAccount.m_getterSetterIdPairs.find(methodBySlotIter->second.m_propertyName);
if (getterSetterIt != m_propertyAccount.m_getterSetterIdPairs.end())
{
CallGetter(getterSetterIt->second.first);
}
}
void PureData::Reflect(AZ::ReflectContext* reflectContext)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext);
if (serializeContext)
{
serializeContext->Class<PureData, Node>()
->Version(0)
;
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<PureData>("PureData", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
;
}
}
}
}
@@ -0,0 +1,112 @@
/*
* 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
#include <ScriptCanvas/Core/Node.h>
#include <ScriptCanvas/Core/Graph.h>
#include <ScriptCanvas/Core/Datum.h>
#include <ScriptCanvas/Data/PropertyTraits.h>
namespace AZ
{
class BehaviorClass;
struct BehaviorValueParameter;
class ReflectContext;
}
namespace ScriptCanvas
{
struct PropertyAccount
{
AZStd::unordered_map<SlotId, Data::GetterWrapper> m_gettersByInputSlot;
AZStd::unordered_map<SlotId, Data::SetterWrapper> m_settersByInputSlot;
// The first slot id of the pair is the Getter SlotId, the second slot id of the pair is the Setter SlotID
AZStd::unordered_map<AZStd::string, AZStd::pair<SlotId, SlotId>> m_getterSetterIdPairs;
};
class PureData
: public Node
{
public:
AZ_COMPONENT(PureData, "{8B80FF54-0786-4FEE-B4A3-12907EBF8B75}", Node);
static void Reflect(AZ::ReflectContext* reflectContext);
static const char* k_getThis;
static const char* k_setThis;
const AZStd::unordered_map<AZStd::string, AZStd::pair<SlotId, SlotId>>& GetPropertyNameSlotMap() const;
~PureData() override;
protected:
void AddInputAndOutputTypeSlot(const Data::Type& type, const void* defaultValue = nullptr);
template<typename DatumType>
void AddDefaultInputAndOutputTypeSlot(DatumType&& defaultValue);
void AddInputTypeAndOutputTypeSlot(const Data::Type& type);
void OnActivate() override;
void OnInputChanged(const Datum& input, const SlotId& id) override;
void MarkDefaultableInput() override {}
AZ_INLINE void OnOutputChanged(const Datum& output) const
{
Slot* slot = GetSlotByName(GetOutputDataName());
if (slot)
{
OnOutputChanged(output, (*slot));
}
}
AZ_INLINE void OnOutputChanged(const Datum& output, const Slot& outputSlot) const
{
PushOutput(output, outputSlot);
}
// push data out
AZ_INLINE void PushThis()
{
auto slotId = GetSlotId(GetInputDataName());
if (auto setDatum = FindDatum(slotId))
{
OnInputChanged(*setDatum, slotId);
}
else
{
SCRIPTCANVAS_REPORT_ERROR((*this), "No input datum in a PureData class %s. You must push your data manually in OnActivate() if no input is connected!");
}
}
AZStd::string_view GetInputDataName() const;
AZStd::string_view GetOutputDataName() const;
void SetInput(const Datum& input, const SlotId& id) override;
void SetInput(Datum&& input, const SlotId& id) override;
void SetProperty(const Datum& input, const SlotId& id);
void CallGetter(const SlotId& getterSlotId);
bool IsConfigured() { return m_configured; }
PropertyAccount m_propertyAccount;
bool m_configured = false;
};
template<typename DatumType>
void PureData::AddDefaultInputAndOutputTypeSlot(DatumType&& defaultValue)
{
AddInputDatumSlot(GetInputDataName(), "", Datum::eOriginality::Original, AZStd::forward<DatumType>(defaultValue));
AddOutputTypeSlot(GetOutputDataName(), "", Data::FromAZType(azrtti_typeid<AZStd::decay_t<DatumType>>()), OutputStorage::Optional);
}
template<>
void PureData::AddDefaultInputAndOutputTypeSlot<Data::Type>(Data::Type&&) = delete;
}
@@ -0,0 +1,129 @@
/*
* 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
#include "Core.h"
#include "Attributes.h"
#include "Contract.h"
#include <AzCore/EBus/EBus.h>
#include <AzCore/RTTI/AttributeReader.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Serialization/ObjectStream.h>
namespace AZ
{
class SerializeContext;
}
namespace ScriptCanvas
{
class Node;
class Graph;
class BehaviorContextObject;
struct SystemComponentConfiguration
{
//! Script Canvas offers infinite loop protection, this allows to specify the max number of iterations to attempt before deciding execution is likely an infinite loop
int m_maxIterationsForInfiniteLoopDetection;
};
////////////////////////////////////////////////////////////////
// SystemRequests
////////////////////////////////////////////////////////////////
class SystemRequests : public AZ::EBusTraits
{
public:
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
using MutexType = AZStd::recursive_mutex;
static const bool LocklessDispatch = true;
//! Create all the components that entity requires to execute the Script Canvas engine
virtual void CreateEngineComponentsOnEntity(AZ::Entity* entity) = 0;
//! Create a graph and attach it to the supplied Entity
virtual Graph* CreateGraphOnEntity(AZ::Entity*) = 0;
//! Create a graph, a pointer to the graph/
//! The Init() function is not called on the graph to remapping of Entity Id's to still work
virtual ScriptCanvas::Graph* MakeGraph() = 0;
virtual ScriptCanvasId FindScriptCanvasId(AZ::Entity* /*graphEntity*/)
{
return ScriptCanvasId();
}
virtual ScriptCanvas::Node* GetNode(const AZ::EntityId&, const AZ::Uuid&) = 0;
//! Given the ClassData for a type create a Script Canvas Node Component on the supplied entity
virtual Node* CreateNodeOnEntity(const AZ::EntityId& entityId, ScriptCanvasId scriptCanvasId, const AZ::Uuid& nodeType) = 0;
template <typename NodeType>
NodeType* GetNode(const AZ::EntityId& nodeId)
{
AZ::Entity* nodeEntity = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(nodeEntity, &AZ::ComponentApplicationRequests::FindEntity, nodeId);
if (nodeEntity)
{
return nodeEntity->FindComponent<NodeType>();
}
return nullptr;
}
//! Adds a mapping of the raw address to an object created by the behavior context to the ScriptCanvas::BehaviorContextObject node that owns that object
virtual void AddOwnedObjectReference(const void* object, BehaviorContextObject* behaviorContextObject) = 0;
//! Looks up the supplied address returns the BehaviorContextObject if it is owned by one
virtual BehaviorContextObject* FindOwnedObjectReference(const void* object) = 0;
//! Removes a mapping of the raw address of an object created by the behavior context to a BehaviorContextObject node
virtual void RemoveOwnedObjectReference(const void* object) = 0;
virtual SystemComponentConfiguration GetSystemComponentConfiguration() = 0;
};
using SystemRequestBus = AZ::EBus<SystemRequests>;
//! Sends out event for when a batch operation happens on the ScriptCanvas side
class BatchOperationNotifications
: public AZ::EBusTraits
{
public:
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
virtual void OnCommandStarted([[maybe_unused]] AZ::Crc32 batchCommandTag) {}
virtual void OnCommandFinished([[maybe_unused]] AZ::Crc32 batchCommandTag) {}
};
using BatchOperationNotificationBus = AZ::EBus<BatchOperationNotifications>;
class ScopedBatchOperation
{
public:
ScopedBatchOperation(AZ::Crc32 commandTag)
: m_batchCommandTag(commandTag)
{
BatchOperationNotificationBus::Broadcast(&BatchOperationNotifications::OnCommandStarted, m_batchCommandTag);
}
~ScopedBatchOperation()
{
BatchOperationNotificationBus::Broadcast(&BatchOperationNotifications::OnCommandFinished, m_batchCommandTag);
}
private:
ScopedBatchOperation(const ScopedBatchOperation&) = delete;
ScopedBatchOperation& operator=(const ScopedBatchOperation&) = delete;
AZ::Crc32 m_batchCommandTag;
};
}
@@ -0,0 +1,41 @@
/*
* 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
#include "Core.h"
#include <AzCore/EBus/EBus.h>
namespace ScriptCanvas
{
enum class ExecuteMode
{
Normal,
UntilNodeIsFoundInStack
};
class SignalInterface : public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
typedef ID BusIdType;
//////////////////////////////////////////////////////////////////////////
virtual void SignalInput(const SlotId& slot) = 0;
virtual void SignalOutput(const SlotId& slot, ExecuteMode mode = ExecuteMode::Normal) = 0;
};
using SignalBus = AZ::EBus<SignalInterface>;
}
@@ -0,0 +1,868 @@
/*
* 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 "Slot.h"
#include "SlotMetadata.h"
#include "Graph.h"
#include "Node.h"
#include "Contracts.h"
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/Utils.h>
#include <ScriptCanvas/Core/Contracts/ExclusivePureDataContract.h>
#include <ScriptCanvas/Variable/VariableBus.h>
#include <ScriptCanvas/Utils/DataUtils.h>
namespace ScriptCanvas
{
/////////
// Slot
/////////
static bool SlotVersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
{
// SlotName
if (classElement.GetVersion() <= 6)
{
auto slotNameElements = AZ::Utils::FindDescendantElements(context, classElement, AZStd::vector<AZ::Crc32>{AZ_CRC("id", 0xbf396750), AZ_CRC("m_name", 0xc08c4427)});
AZStd::string slotName;
if (slotNameElements.empty() || !slotNameElements.front()->GetData(slotName))
{
return false;
}
classElement.AddElementWithData(context, "slotName", slotName);
}
// Index fields
if (classElement.GetVersion() <= 8)
{
classElement.RemoveElementByName(AZ_CRC("index", 0x80736701));
}
// Dynamic Type Fields
if (classElement.GetVersion() <= 9)
{
classElement.AddElementWithData(context, "DynamicTypeOverride", DynamicDataType::None);
}
else if (classElement.GetVersion() < 11)
{
AZ::SerializeContext::DataElementNode* subElement = classElement.FindSubElement(AZ_CRC("dataTypeOverride", 0x7f1765d9));
int enumValue = 0;
if (subElement->GetData(enumValue))
{
if (enumValue != 0)
{
classElement.AddElementWithData(context, "DynamicTypeOverride", DynamicDataType::Container);
}
else
{
classElement.AddElementWithData(context, "DynamicTypeOverride", DynamicDataType::None);
}
}
classElement.RemoveElementByName(AZ_CRC("dataTypeOverride", 0x7f1765d9));
}
// DisplayDataType
if (classElement.GetVersion() < 12)
{
classElement.AddElementWithData(context, "DisplayDataType", Data::Type::Invalid());
}
// Descriptor
if (classElement.GetVersion() <= 13)
{
AZ::SerializeContext::DataElementNode* subElement = classElement.FindSubElement(AZ_CRC("type", 0x8cde5729));
int enumValue = 0;
if (subElement && subElement->GetData(enumValue))
{
CombinedSlotType combinedSlotType = static_cast<CombinedSlotType>(enumValue);
SlotDescriptor slotDescriptor = SlotDescriptor(combinedSlotType);
classElement.AddElementWithData(context, "Descriptor", slotDescriptor);
bool isLatent = (combinedSlotType == CombinedSlotType::LatentOut);
classElement.AddElementWithData(context, "IsLatent", isLatent);
}
classElement.RemoveElementByName(AZ_CRC("type", 0x8cde5729));
}
// DataType
if (classElement.GetVersion() <= 15)
{
AZ::SerializeContext::DataElementNode* subElement = classElement.FindSubElement(AZ_CRC("Descriptor", 0x03927602));
Slot::DataType dataType = Slot::DataType::NoData;
SlotDescriptor slotDescriptor;
if (subElement && subElement->GetData(slotDescriptor))
{
if (slotDescriptor.IsData() && dataType == Slot::DataType::NoData)
{
dataType = Slot::DataType::Data;
}
}
classElement.AddElementWithData(context, "DataType", dataType);
}
// This data field wasn't actually being initalized correctly So need to re-version convert.
else if (classElement.GetVersion() <= 17)
{
AZ::SerializeContext::DataElementNode* subElement = classElement.FindSubElement(AZ_CRC("Descriptor", 0x03927602));
Slot::DataType dataType = Slot::DataType::NoData;
SlotDescriptor slotDescriptor;
if (subElement && subElement->GetData(slotDescriptor))
{
if (slotDescriptor.IsData() && dataType == Slot::DataType::NoData)
{
dataType = Slot::DataType::Data;
}
}
classElement.RemoveElementByName(AZ_CRC("DataType", 0x8539af66));
classElement.AddElementWithData(context, "DataType", dataType);
}
if (classElement.GetVersion() <= 17)
{
classElement.RemoveElementByName(AZ_CRC("nodeId", 0x9ce63325));
}
return true;
}
void Slot::Reflect(AZ::ReflectContext* reflection)
{
SlotId::Reflect(reflection);
Contract::Reflect(reflection);
RestrictedTypeContract::Reflect(reflection);
DynamicTypeContract::Reflect(reflection);
SlotTypeContract::Reflect(reflection);
ConnectionLimitContract::Reflect(reflection);
DisallowReentrantExecutionContract::Reflect(reflection);
DisplayGroupConnectedSlotLimitContract::Reflect(reflection);
ContractRTTI::Reflect(reflection);
IsReferenceTypeContract::Reflect(reflection);
SlotMetadata::Reflect(reflection);
SupportsMethodContract::Reflect(reflection);
MathOperatorContract::Reflect(reflection);
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection);
if (serializeContext)
{
serializeContext->Class<SlotDescriptor>()
->Version(1)
->Field("ConnectionType", &SlotDescriptor::m_connectionType)
->Field("SlotType", &SlotDescriptor::m_slotType)
;
serializeContext->Class<Slot>()
->Version(18, &SlotVersionConverter)
->Field("id", &Slot::m_id)
->Field("DynamicTypeOverride", &Slot::m_dynamicDataType)
->Field("contracts", &Slot::m_contracts)
->Field("slotName", &Slot::m_name)
->Field("toolTip", &Slot::m_toolTip)
->Field("DisplayDataType", &Slot::m_displayDataType)
->Field("DisplayGroup", &Slot::m_displayGroup)
->Field("Descriptor", &Slot::m_descriptor)
->Field("IsLatent", &Slot::m_isLatentSlot)
->Field("DynamicGroup", &Slot::m_dynamicGroup)
->Field("DataType", &Slot::m_dataType)
->Field("IsReference", &Slot::m_isVariableReference)
->Field("VariableReference", &Slot::m_variableReference)
;
}
}
Slot::Slot(const SlotConfiguration& slotConfiguration)
: m_name(slotConfiguration.m_name)
, m_toolTip(slotConfiguration.m_toolTip)
, m_isLatentSlot(slotConfiguration.m_isLatent)
, m_descriptor(slotConfiguration.GetSlotDescriptor())
, m_dynamicDataType(DynamicDataType::None)
, m_id(slotConfiguration.m_slotId)
{
if (!slotConfiguration.m_displayGroup.empty())
{
m_displayGroup = AZ::Crc32(slotConfiguration.m_displayGroup.c_str());
}
// Add the slot type contract by default, It is used for filtering input/output slots and flow/data slots
m_contracts.emplace_back(AZStd::make_unique<SlotTypeContract>());
// Every DataIn slot has a contract validating that only 1 connection from any PureData node is allowed
if (IsData() && IsInput())
{
AddContract({ []() { return aznew ExclusivePureDataContract(); } });
}
for (const auto& contractDesc : slotConfiguration.m_contractDescs)
{
AddContract(contractDesc);
}
if (const DataSlotConfiguration* dataSlotConfiguration = azrtti_cast<const DataSlotConfiguration*>(&slotConfiguration))
{
m_dataType = DataType::Data;
}
if (const DynamicDataSlotConfiguration* dynamicDataSlotConfiguration = azrtti_cast<const DynamicDataSlotConfiguration*>(&slotConfiguration))
{
m_dataType = DataType::Data;
m_dynamicDataType = dynamicDataSlotConfiguration->m_dynamicDataType;
m_dynamicGroup = dynamicDataSlotConfiguration->m_dynamicGroup;
}
}
Slot::Slot(const Slot& other)
: m_name(other.m_name)
, m_toolTip(other.m_toolTip)
, m_displayGroup(other.m_displayGroup)
, m_dynamicGroup(other.m_dynamicGroup)
, m_isLatentSlot(other.m_isLatentSlot)
, m_descriptor(other.m_descriptor)
, m_isVariableReference(other.m_isVariableReference)
, m_dataType(other.m_dataType)
, m_variableReference(other.m_variableReference)
, m_dynamicDataType(other.m_dynamicDataType)
, m_id(other.m_id)
, m_node(other.m_node)
{
for (auto& otherContract : other.m_contracts)
{
m_contracts.emplace_back(AZ::EntityUtils::GetApplicationSerializeContext()->CloneObject(otherContract.get()));
}
SetDisplayType(other.m_displayDataType);
}
Slot::Slot(Slot&& slot)
: m_name(AZStd::move(slot.m_name))
, m_toolTip(AZStd::move(slot.m_toolTip))
, m_displayGroup(AZStd::move(slot.m_displayGroup))
, m_dynamicGroup(AZStd::move(slot.m_dynamicGroup))
, m_isLatentSlot(AZStd::move(slot.m_isLatentSlot))
, m_descriptor(AZStd::move(slot.m_descriptor))
, m_isVariableReference(AZStd::move(slot.m_isVariableReference))
, m_dataType(AZStd::move(slot.m_dataType))
, m_variableReference(AZStd::move(slot.m_variableReference))
, m_dynamicDataType(AZStd::move(slot.m_dynamicDataType))
, m_displayDataType(AZStd::move(slot.m_displayDataType))
, m_id(AZStd::move(slot.m_id))
, m_node(AZStd::move(slot.m_node))
, m_contracts(AZStd::move(slot.m_contracts))
{
SetDisplayType(slot.m_displayDataType);
}
Slot::~Slot()
{
VariableNotificationBus::Handler::BusDisconnect();
}
Slot& Slot::operator=(const Slot& slot)
{
m_name = slot.m_name;
m_toolTip = slot.m_toolTip;
m_displayGroup = slot.m_displayGroup;
m_dynamicGroup = slot.m_dynamicGroup;
m_isLatentSlot = slot.m_isLatentSlot;
m_descriptor = slot.m_descriptor;
m_isVariableReference = slot.m_isVariableReference;
m_dataType = slot.m_dataType;
m_variableReference = slot.m_variableReference;
m_dynamicDataType = slot.m_dynamicDataType;
m_displayDataType = slot.m_displayDataType;
m_id = slot.m_id;
m_node = slot.m_node;
for (auto& otherContract : slot.m_contracts)
{
m_contracts.emplace_back(AZ::EntityUtils::GetApplicationSerializeContext()->CloneObject(otherContract.get()));
}
SetDisplayType(slot.m_displayDataType);
return *this;
}
void Slot::AddContract(const ContractDescriptor& contractDesc)
{
if (contractDesc.m_createFunc)
{
Contract* newContract = contractDesc.m_createFunc();
if (newContract)
{
m_contracts.emplace_back(newContract);
}
}
}
void Slot::ConvertToLatentExecutionOut()
{
if (IsExecution() && IsOutput())
{
m_isLatentSlot = true;
}
}
AZ::EntityId Slot::GetNodeId() const
{
return GetNode()->GetEntityId();
}
void Slot::SetNode(Node* node)
{
m_node = node;
}
void Slot::InitializeVariables()
{
if (IsVariableReference())
{
m_variable = m_node->FindGraphVariable(m_variableReference);
if (m_variable)
{
VariableNotificationBus::Handler::BusConnect(m_variable->GetGraphScopedId());
if (IsInput())
{
m_node->OnInputChanged((*m_variable->GetDatum()), GetId());
}
}
else
{
SCRIPTCANVAS_REPORT_ERROR((*m_node), "Node (%s) is attempting to execute using an invalid Variable Reference", m_node->GetNodeName().c_str());
}
}
}
Endpoint Slot::GetEndpoint() const
{
return Endpoint(GetNode()->GetEntityId(), GetId());
}
Data::Type Slot::GetDataType() const
{
Data::Type retVal = m_node->GetSlotDataType(GetId());
return retVal;
}
bool Slot::IsConnected() const
{
return GetNode()->IsConnected(GetId());
}
bool Slot::IsData() const
{
return m_descriptor.IsData();
}
const Datum* Slot::FindDatum() const
{
const Datum* datum = m_node->FindDatum(GetId());
return datum;
}
void Slot::FindModifiableDatumView(ModifiableDatumView& datumView)
{
m_node->FindModifiableDatumView(GetId(), datumView);
}
bool Slot::IsVariableReference() const
{
return m_isVariableReference || m_dataType == DataType::VariableReference;
}
bool Slot::CanConvertToValue() const
{
return CanConvertTypes() && m_isVariableReference;
}
bool Slot::ConvertToValue()
{
if (CanConvertToValue())
{
m_isVariableReference = false;
m_variableReference = ScriptCanvas::VariableId();
m_variable = nullptr;
if (m_node)
{
m_node->OnSlotConvertedToValue(GetId());
}
}
return !m_isVariableReference;
}
bool Slot::CanConvertTypes() const
{
// Don't allow VariableId's to be variable references.
return m_dataType == DataType::Data
&& GetDataType() != Data::Type::BehaviorContextObject(GraphScopedVariableId::TYPEINFO_Uuid());
}
bool Slot::CanConvertToReference() const
{
return CanConvertTypes() && !m_isVariableReference && !m_node->HasConnectedNodes((*this));
}
bool Slot::ConvertToReference()
{
if (CanConvertToReference())
{
m_isVariableReference = true;
if (m_node)
{
m_node->OnSlotConvertedToReference(GetId());
}
}
return m_isVariableReference;
}
void Slot::SetVariableReference(const VariableId& variableId)
{
if (!IsVariableReference() && !ConvertToReference())
{
return;
}
if (m_variableReference == variableId)
{
return;
}
m_variableReference = variableId;
m_variable = nullptr;
VariableNotificationBus::Handler::BusDisconnect();
if (IsDynamicSlot())
{
if (!HasDisplayType())
{
GraphVariable* variable = m_node->FindGraphVariable(m_variableReference);
ScriptCanvas::Data::Type displayType = variable ? variable->GetDataType() : ScriptCanvas::Data::Type::Invalid();
AZ::Crc32 dynamicGroup = GetDynamicGroup();
if (dynamicGroup != AZ::Crc32())
{
if (m_node->HasConcreteDisplayType(dynamicGroup))
{
m_node->SetDisplayType(dynamicGroup, displayType);
}
}
else
{
SetDisplayType(displayType);
}
}
else if (!m_variableReference.IsValid())
{
m_node->SanityCheckDynamicDisplay();
}
}
if (m_variableReference.IsValid())
{
InitializeVariables();
}
NodeNotificationsBus::Event(m_node->GetEntityId(), &NodeNotifications::OnInputChanged, GetId());
EndpointNotificationBus::Event(Endpoint(m_node->GetEntityId(), GetId()), &EndpointNotifications::OnEndpointReferenceChanged, m_variableReference);
}
const VariableId& Slot::GetVariableReference() const
{
return m_variableReference;
}
GraphVariable* Slot::GetVariable() const
{
return m_variable;
}
void Slot::ClearVariableReference()
{
SetVariableReference(VariableId());
}
bool Slot::IsExecution() const
{
return m_descriptor.IsExecution();
}
bool Slot::IsInput() const
{
return m_descriptor.IsInput();
}
bool Slot::IsOutput() const
{
return m_descriptor.IsOutput();
}
ScriptCanvas::ConnectionType Slot::GetConnectionType() const
{
return m_descriptor.m_connectionType;
}
bool Slot::IsLatent() const
{
return m_isLatentSlot;
}
void Slot::OnVariableValueChanged()
{
m_node->OnInputChanged((*m_variable->GetDatum()), GetId());
}
void Slot::SetDynamicDataType(DynamicDataType dynamicDataType)
{
AZ_Assert(m_dynamicDataType == DynamicDataType::None, "Set Dynamic Data Type is meant to be used for a node wise version conversion step. Not as a run time reconfiguration of a dynamic type.");
if (m_dynamicDataType == DynamicDataType::None)
{
m_dynamicDataType = dynamicDataType;
}
}
bool Slot::IsDynamicSlot() const
{
return m_dynamicDataType != DynamicDataType::None;
}
void Slot::SetDisplayType(ScriptCanvas::Data::Type displayType)
{
if ((m_displayDataType.IsValid() && !displayType.IsValid())
|| (!m_displayDataType.IsValid() && displayType.IsValid()))
{
// Confirm that the type we are display as conforms to what our underlying type says we
// should be.
if (displayType.IsValid() && IsDynamicSlot())
{
AZ::TypeId typeId = displayType.GetAZType();
bool isContainerType = AZ::Utils::IsContainerType(typeId);
if (m_dynamicDataType == DynamicDataType::Value && isContainerType)
{
return;
}
else if (m_dynamicDataType == DynamicDataType::Container && !isContainerType)
{
return;
}
}
m_displayDataType = displayType;
// For dynamic slots we want to manipulate the underlying data a little to simplify down the usages.
// i.e. Just setting the display type of the slot should allow the datum to function as that type.
//
// For non-dynamic slots, I don't want to do anything since there might be some specialization
// going on that I don't want to stomp on.
if (IsDynamicSlot() && IsInput())
{
ModifiableDatumView datumView;
GetNode()->ModifyUnderlyingSlotDatum(GetId(), datumView);
if (datumView.IsValid())
{
if (!datumView.IsType(m_displayDataType))
{
AZStd::string label = datumView.GetDatum()->GetLabel();
if (m_displayDataType.IsValid())
{
Datum sourceDatum(m_displayDataType, ScriptCanvas::Datum::eOriginality::Original);
sourceDatum.SetToDefaultValueOfType();
datumView.ReconfigureDatumTo(AZStd::move(sourceDatum));
}
else
{
datumView.ReconfigureDatumTo(AZStd::move(Datum()));
}
datumView.SetLabel(label);
}
}
}
if (m_node)
{
m_node->SignalSlotDisplayTypeChanged(m_id, GetDisplayType());
}
}
}
void Slot::ClearDisplayType()
{
if (IsDynamicSlot())
{
SetDisplayType(Data::Type::Invalid());
}
}
ScriptCanvas::Data::Type Slot::GetDisplayType() const
{
return m_displayDataType;
}
bool Slot::HasDisplayType() const
{
return m_displayDataType.IsValid();
}
AZ::Crc32 Slot::GetDisplayGroup() const
{
return m_displayGroup;
}
void Slot::SetDisplayGroup(AZStd::string displayGroup)
{
m_displayGroup = AZ::Crc32(displayGroup);
}
AZ::Crc32 Slot::GetDynamicGroup() const
{
return m_dynamicGroup;
}
AZ::Outcome<void, AZStd::string> Slot::IsTypeMatchFor(const Slot& otherSlot) const
{
AZ::Outcome<void, AZStd::string> matchForOutcome;
ScriptCanvas::Data::Type myType = GetDataType();
ScriptCanvas::Data::Type otherType = otherSlot.GetDataType();
if (otherType.IsValid())
{
if (IsDynamicSlot() && GetDynamicGroup() != AZ::Crc32())
{
matchForOutcome = m_node->IsValidTypeForGroup(GetDynamicGroup(), otherType);
if (!matchForOutcome.IsSuccess())
{
return matchForOutcome;
}
}
matchForOutcome = IsTypeMatchFor(otherType);
if (!matchForOutcome)
{
return matchForOutcome;
}
}
if (myType.IsValid())
{
if (otherSlot.IsDynamicSlot() && otherSlot.GetDynamicGroup() != AZ::Crc32())
{
matchForOutcome = otherSlot.m_node->IsValidTypeForGroup(otherSlot.GetDynamicGroup(), myType);
if (!matchForOutcome)
{
return matchForOutcome;
}
}
matchForOutcome = otherSlot.IsTypeMatchFor(myType);
if (!matchForOutcome)
{
return matchForOutcome;
}
}
// Container check is either based on the concrete type associated with the slot.
// Or the dynamic display type if no concrete type has been associated.
bool isMyTypeContainer = AZ::Utils::IsContainerType(ScriptCanvas::Data::ToAZType(myType)) || (IsDynamicSlot() && !HasDisplayType() && GetDynamicDataType() == DynamicDataType::Container);
bool isOtherTypeContainer = AZ::Utils::IsContainerType(ScriptCanvas::Data::ToAZType(otherType)) || (otherSlot.IsDynamicSlot() && !otherSlot.HasDisplayType() && otherSlot.GetDynamicDataType() == DynamicDataType::Container);
// Confirm that our dynamic typing matches to the other. Or that hard types match the other in terms of dynamic slot types.
if (IsDynamicSlot())
{
if (GetDynamicDataType() == DynamicDataType::Container && !isOtherTypeContainer)
{
if (otherSlot.HasDisplayType() || otherSlot.GetDynamicDataType() != DynamicDataType::Any)
{
if (otherType.IsValid())
{
return AZ::Failure(AZStd::string::format("%s is not a valid Container type.", ScriptCanvas::Data::GetName(otherType).c_str()));
}
else
{
return AZ::Failure<AZStd::string>("Cannot connect Dynamic Container to Dynamic Value type.");
}
}
}
else if (GetDynamicDataType() == DynamicDataType::Value && isOtherTypeContainer)
{
return AZ::Failure(AZStd::string::format("%s is a Container type and not a Value type.", ScriptCanvas::Data::GetName(otherType).c_str()));
}
}
if (otherSlot.IsDynamicSlot())
{
if (otherSlot.GetDynamicDataType() == DynamicDataType::Container && !isMyTypeContainer)
{
if (HasDisplayType() || GetDynamicDataType() != DynamicDataType::Any)
{
if (myType.IsValid())
{
return AZ::Failure(AZStd::string::format("%s is not a valid Container type.", ScriptCanvas::Data::GetName(myType).c_str()));
}
else
{
return AZ::Failure<AZStd::string>("Cannot connect Dynamic Container to Dynamic Value type.");
}
}
}
else if (otherSlot.GetDynamicDataType() == DynamicDataType::Value && isMyTypeContainer)
{
return AZ::Failure(AZStd::string::format("%s is a Container type and not a Value type.", ScriptCanvas::Data::GetName(myType).c_str()));
}
}
// If either side is dynamic, and doesn't have a display type, we can stop checking here since we passed all the negative cases.
// And we know that the hard type match will fail.
if ((IsDynamicSlot() && !HasDisplayType())
|| (otherSlot.IsDynamicSlot() && !otherSlot.HasDisplayType()))
{
return AZ::Success();
}
// At this point we need to confirm the types are a match.
if (myType.IS_A(otherType))
{
return AZ::Success();
}
return AZ::Failure(AZStd::string::format("%s is not a type match for %s", ScriptCanvas::Data::GetName(myType).c_str(), ScriptCanvas::Data::GetName(otherType).c_str()));
}
AZ::Outcome<void, AZStd::string> Slot::IsTypeMatchFor(const ScriptCanvas::Data::Type& dataType) const
{
if (IsExecution())
{
return AZ::Failure<AZStd::string>("Execution slot cannot match Data types.");
}
AZ::Outcome<void, AZStd::string> failureReason;
bool contractsAllowType = true;
for (const auto& contract : m_contracts)
{
failureReason = contract->EvaluateForType(dataType);
if (!failureReason)
{
return failureReason;
}
}
if (GetDynamicDataType() == DynamicDataType::Any
&& !HasDisplayType())
{
return AZ::Success();
}
if (IsDynamicSlot())
{
auto outcomeResult = DataUtils::MatchesDynamicDataTypeOutcome(GetDynamicDataType(), dataType);
if (!outcomeResult.IsSuccess())
{
return outcomeResult;
}
else if (!HasDisplayType())
{
return AZ::Success();
}
}
// At this point we need to confirm the types are a match.
if (GetDataType().IS_A(dataType))
{
return AZ::Success();
}
return AZ::Failure(AZStd::string::format("%s is not a type match for %s", ScriptCanvas::Data::GetName(GetDataType()).c_str(), ScriptCanvas::Data::GetName(dataType).c_str()));
}
void Slot::Rename(AZStd::string_view newName)
{
if (m_name != newName)
{
m_name = newName;
ModifiableDatumView datumView;
if (m_node)
{
m_node->ModifyUnderlyingSlotDatum(GetId(), datumView);
if (datumView.IsValid())
{
datumView.SetLabel(m_name);
}
}
SignalRenamed();
}
}
void Slot::SignalRenamed()
{
NodeNotificationsBus::Event(GetNodeId(), &ScriptCanvas::NodeNotifications::OnSlotRenamed, GetId(), GetName());
}
void Slot::SignalTypeChanged(const ScriptCanvas::Data::Type& dataType)
{
GetNode()->SignalSlotDisplayTypeChanged(GetId(), dataType);
}
void Slot::UpdateDatumVisibility()
{
ScriptCanvas::ModifiableDatumView datumView;
GetNode()->ModifyUnderlyingSlotDatum(GetId(), datumView);
datumView.SetVisibility(IsConnected() ? AZ::Edit::PropertyVisibility::Hide : AZ::Edit::PropertyVisibility::ShowChildrenOnly);
}
TransientSlotIdentifier Slot::GetTransientIdentifier() const
{
return m_node->ConstructTransientIdentifier((*this));
}
void Slot::SetDynamicGroup(const AZ::Crc32& dynamicGroup)
{
m_dynamicGroup = dynamicGroup;
}
}
@@ -0,0 +1,218 @@
/*
* 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
#include <AzCore/EBus/EBus.h>
#include <AzCore/std/string/string_view.h>
#include <ScriptCanvas/Core/Contracts/SlotTypeContract.h>
#include <ScriptCanvas/Core/Core.h>
#include <ScriptCanvas/Core/Endpoint.h>
#include <ScriptCanvas/Core/SlotConfigurations.h>
#include <ScriptCanvas/Core/ModifiableDatumView.h>
#include <ScriptCanvas/Data/Data.h>
#include <ScriptCanvas/Variable/VariableCore.h>
#include <ScriptCanvas/Variable/VariableBus.h>
namespace ScriptCanvas
{
class Contract;
class Node;
struct TransientSlotIdentifier
{
AZStd::string m_name;
SlotDescriptor m_slotDescriptor;
int m_index = 0;
};
class Slot final
: public VariableNotificationBus::Handler
{
friend class Node;
public:
enum class DataType : AZ::s32
{
NoData,
Data,
VariableReference
};
AZ_CLASS_ALLOCATOR(Slot, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(Slot, "{FBFE0F02-4C26-475F-A28B-18D3A533C13C}");
static void Reflect(AZ::ReflectContext* reflection);
Slot() = default;
Slot(const Slot& slot);
Slot(Slot&& slot);
Slot(const SlotConfiguration& slotConfiguration);
~Slot();
Slot& operator=(const Slot& slot);
void AddContract(const ContractDescriptor& contractDesc);
template<typename T>
void RemoveContract()
{
AZ::Uuid contractType = azrtti_typeid<T>();
auto contractIter = m_contracts.begin();
while (contractIter != m_contracts.end())
{
if (azrtti_typeid(contractIter->get()) == contractType)
{
m_contracts.erase(contractIter);
break;
}
++contractIter;
}
}
AZStd::vector<AZStd::unique_ptr<Contract>>& GetContracts() { return m_contracts; }
const AZStd::vector<AZStd::unique_ptr<Contract>>& GetContracts() const { return m_contracts; }
// ConvertToLatentExecutionOut
//
// Mainly here to limit scope of what manipulation can be done to the slots. We need to version convert the slots
// but at a higher tier, so instead of allowing the type to be set, going to just make this specific function which does
// the conversion we are after.
void ConvertToLatentExecutionOut();
////
const SlotDescriptor& GetDescriptor() const { return m_descriptor; }
const SlotId& GetId() const { return m_id; }
const Node* GetNode() const { return m_node; }
Node* GetNode() { return m_node; }
Endpoint GetEndpoint() const;
AZ::EntityId GetNodeId() const;
void SetNode(Node* node);
void InitializeVariables();
const AZStd::string& GetName() const { return m_name; }
const AZStd::string& GetToolTip() const { return m_toolTip; }
Data::Type GetDataType() const;
bool IsConnected() const;
bool IsData() const;
const Datum* FindDatum() const;
void FindModifiableDatumView(ModifiableDatumView& datumView);
// If you are data. You could be a reference pin(i.e. must be a variable)
// Or a value data pin.
bool IsVariableReference() const;
bool CanConvertTypes() const;
bool CanConvertToValue() const;
bool ConvertToValue();
bool CanConvertToReference() const;
bool ConvertToReference();
void SetVariableReference(const VariableId& variableId);
const VariableId& GetVariableReference() const;
GraphVariable* GetVariable() const;
void ClearVariableReference();
bool IsExecution() const;
bool IsInput() const;
bool IsOutput() const;
ScriptCanvas::ConnectionType GetConnectionType() const;
bool IsLatent() const;
// VariableNotificationBus
void OnVariableValueChanged() override;
////
// Here to allow conversion of the previously untyped any slots into the dynamic type any.
void SetDynamicDataType(DynamicDataType dynamicDataType);
////
const DynamicDataType& GetDynamicDataType() const { return m_dynamicDataType; }
bool IsDynamicSlot() const;
void SetDisplayType(Data::Type displayType);
void ClearDisplayType();
Data::Type GetDisplayType() const;
bool HasDisplayType() const;
AZ::Crc32 GetDisplayGroup() const;
// Should only be used for updating slots. And never really done at runtime as slots
// won't be re-arranged.
void SetDisplayGroup(AZStd::string displayGroup);
AZ::Crc32 GetDynamicGroup() const;
AZ::Outcome<void, AZStd::string> IsTypeMatchFor(const Slot& slot) const;
AZ::Outcome<void, AZStd::string> IsTypeMatchFor(const Data::Type& dataType) const;
void Rename(AZStd::string_view slotName);
void SignalRenamed();
void SignalTypeChanged(const ScriptCanvas::Data::Type& dataType);
void UpdateDatumVisibility();
// Editor Fields
// Returns information which can be used to identify this slot in a 'transient' fashion.
// This data should not be stored and used for long term retrieval but should be valid within a single session
// to identify the same slot between different nodes.
TransientSlotIdentifier GetTransientIdentifier() const;
////
protected:
void SetDynamicGroup(const AZ::Crc32& dynamicGroup);
AZStd::string m_name;
AZStd::string m_toolTip;
AZ::Crc32 m_displayGroup;
AZ::Crc32 m_dynamicGroup;
bool m_isLatentSlot = false;
SlotDescriptor m_descriptor;
bool m_isVariableReference = false;
DataType m_dataType = DataType::NoData;
VariableId m_variableReference;
GraphVariable* m_variable = nullptr;
DynamicDataType m_dynamicDataType{ DynamicDataType::None };
ScriptCanvas::Data::Type m_displayDataType{ ScriptCanvas::Data::Type::Invalid() };
SlotId m_id;
Node* m_node;
AZStd::vector<AZStd::unique_ptr<Contract>> m_contracts;
};
} // namespace ScriptCanvas
@@ -0,0 +1,43 @@
/*
* 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
#include <ScriptCanvas/Core/SlotConfigurations.h>
namespace ScriptCanvas
{
namespace CommonSlots
{
struct GeneralInSlot
: public ExecutionSlotConfiguration
{
static constexpr const char* GetName() { return "In"; }
GeneralInSlot()
: ExecutionSlotConfiguration(GetName(), ConnectionType::Input)
{
}
};
struct GeneralOutSlot
: public ExecutionSlotConfiguration
{
static constexpr const char* GetName() { return "Out"; }
GeneralOutSlot()
: ExecutionSlotConfiguration(GetName(), ConnectionType::Output)
{
}
};
}
}
@@ -0,0 +1,116 @@
/*
* 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 <ScriptCanvas/Core/SlotConfigurations.h>
#include <ScriptCanvas/Data/DataRegistry.h>
namespace ScriptCanvas
{
//////////////////
// SlotTypeUtils
//////////////////
AZStd::pair<ConnectionType, SlotTypeDescriptor> SlotTypeUtils::BreakApartSlotType(CombinedSlotType slotType)
{
AZStd::pair<ConnectionType, SlotTypeDescriptor> brokenDescription;
switch (slotType)
{
case CombinedSlotType::ExecutionIn:
brokenDescription.first = ConnectionType::Input;
brokenDescription.second = SlotTypeDescriptor::Execution;
break;
case CombinedSlotType::ExecutionOut:
brokenDescription.first = ConnectionType::Output;
brokenDescription.second = SlotTypeDescriptor::Execution;
break;
case CombinedSlotType::LatentOut:
brokenDescription.first = ConnectionType::Output;
brokenDescription.second = SlotTypeDescriptor::Execution;
break;
case CombinedSlotType::DataIn:
brokenDescription.first = ConnectionType::Input;
brokenDescription.second = SlotTypeDescriptor::Data;
break;
case CombinedSlotType::DataOut:
brokenDescription.first = ConnectionType::Output;
brokenDescription.second = SlotTypeDescriptor::Data;
break;
default:
brokenDescription.first = ConnectionType::Unknown;
brokenDescription.second = SlotTypeDescriptor::Unknown;
break;
}
return brokenDescription;
}
//////////////////////
// SlotConfiguration
//////////////////////
SlotConfiguration::SlotConfiguration(SlotTypeDescriptor slotType)
: m_slotId(AZ::Uuid::CreateRandom())
{
m_slotDescriptor.m_slotType = slotType;
}
void SlotConfiguration::SetConnectionType(ConnectionType connectionType)
{
m_slotDescriptor.m_connectionType = connectionType;
}
//////////////////////////
// DataSlotConfiguration
//////////////////////////
DataSlotConfiguration::DataSlotConfiguration(Datum&& datum)
: SlotConfiguration(SlotTypeDescriptor::Data)
, m_datum(AZStd::move(datum))
{
}
DataSlotConfiguration::DataSlotConfiguration(Data::Type dataType)
: SlotConfiguration(SlotTypeDescriptor::Data)
, m_datum(dataType, Datum::eOriginality::Original, nullptr, AZ::Uuid::CreateNull())
{
}
DataSlotConfiguration::DataSlotConfiguration(Data::Type dataType, AZStd::string name, ConnectionType connectionType)
: DataSlotConfiguration(dataType)
{
m_name = name;
SetConnectionType(connectionType);
}
void DataSlotConfiguration::SetType(Data::Type dataType)
{
m_datum.SetType(dataType);
}
void DataSlotConfiguration::SetType(const AZ::BehaviorParameter& typeDesc)
{
auto dataRegistry = GetDataRegistry();
Data::Type scType = !AZ::BehaviorContextHelper::IsStringParameter(typeDesc) ? Data::FromAZType(typeDesc.m_typeId) : Data::Type::String();
auto typeIter = dataRegistry->m_creatableTypes.find(scType);
if (typeIter != dataRegistry->m_creatableTypes.end())
{
m_datum.SetType(scType);
}
}
/////////////////////////////////
// DynamicDataSlotConfiguration
/////////////////////////////////
}
@@ -0,0 +1,310 @@
/*
* 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
#include <AzCore/std/utils.h>
#include <ScriptCanvas/Core/Contracts/SlotTypeContract.h>
#include <ScriptCanvas/Core/Datum.h>
namespace ScriptCanvas
{
enum class CombinedSlotType : AZ::s32
{
None = 0,
ExecutionIn,
ExecutionOut,
DataIn,
DataOut,
LatentOut,
};
enum class ConnectionType : AZ::s32
{
Unknown = 0,
Input,
Output
};
enum class SlotTypeDescriptor : AZ::s32
{
Unknown = 0,
Execution,
Data
};
class SlotTypeUtils
{
public:
static AZStd::pair<ConnectionType, SlotTypeDescriptor> BreakApartSlotType(CombinedSlotType slotType);
};
enum class DynamicDataType : AZ::s32
{
None = 0,
Value,
Container,
Any
};
struct SlotDescriptor
{
AZ_CLASS_ALLOCATOR(SlotDescriptor, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(SlotDescriptor, "{FBF1C3A7-AA74-420F-BBE4-29F78D6EA262}");
constexpr SlotDescriptor() = default;
SlotDescriptor(CombinedSlotType slotType)
{
AZStd::pair<ConnectionType, SlotTypeDescriptor> brokenDescriptor = SlotTypeUtils::BreakApartSlotType(slotType);
m_connectionType = brokenDescriptor.first;
m_slotType = brokenDescriptor.second;
}
constexpr SlotDescriptor(ConnectionType connectionType, SlotTypeDescriptor slotType)
: m_connectionType(connectionType)
, m_slotType(slotType)
{
}
bool CanConnectTo(const SlotDescriptor& slotDescriptor) const
{
bool validConnection = true;
if (m_slotType != slotDescriptor.m_slotType)
{
validConnection = false;
}
else
{
if (m_connectionType == ConnectionType::Input)
{
if (slotDescriptor.m_connectionType != ConnectionType::Output)
{
validConnection = false;
}
}
else if (m_connectionType == ConnectionType::Output)
{
if (slotDescriptor.m_connectionType != ConnectionType::Input)
{
validConnection = false;
}
}
}
return validConnection;
}
constexpr bool operator==(const SlotDescriptor& other) const
{
return m_connectionType == other.m_connectionType
&& m_slotType == other.m_slotType;
}
constexpr bool operator!=(const SlotDescriptor& other) const
{
return !((*this) == other);
}
constexpr bool IsInput() const
{
return m_connectionType == ConnectionType::Input;
}
constexpr bool IsOutput() const
{
return m_connectionType == ConnectionType::Output;
}
constexpr bool IsData() const
{
return m_slotType == SlotTypeDescriptor::Data;
}
constexpr bool IsExecution() const
{
return m_slotType == SlotTypeDescriptor::Execution;
}
constexpr bool IsValid() const
{
return m_connectionType != ConnectionType::Unknown
&& m_slotType != SlotTypeDescriptor::Unknown;
}
ConnectionType m_connectionType = ConnectionType::Unknown;
SlotTypeDescriptor m_slotType = SlotTypeDescriptor::Unknown;
};
template<ConnectionType ConnectionName = ConnectionType::Unknown, SlotTypeDescriptor SlotTypeName = SlotTypeDescriptor::Unknown>
struct DescriptorHelper
: public SlotDescriptor
{
constexpr DescriptorHelper()
: SlotDescriptor(ConnectionName, SlotTypeName)
{
}
};
////
// Predefines for ease of use
struct SlotDescriptors
{
public:
struct ExecutionInDescriptor : DescriptorHelper<ConnectionType::Input, SlotTypeDescriptor::Execution> {};
struct ExecutionOutDescriptor : DescriptorHelper<ConnectionType::Output, SlotTypeDescriptor::Execution> {};
struct DataInDescriptor : DescriptorHelper<ConnectionType::Input, SlotTypeDescriptor::Data> {};
struct DataOutDescriptor : DescriptorHelper<ConnectionType::Output, SlotTypeDescriptor::Data> {};
static constexpr ExecutionInDescriptor ExecutionIn()
{
return ExecutionInDescriptor();
}
static constexpr ExecutionOutDescriptor ExecutionOut()
{
return ExecutionOutDescriptor();
}
static constexpr DataInDescriptor DataIn()
{
return DataInDescriptor();
}
static constexpr DataOutDescriptor DataOut()
{
return DataOutDescriptor();
}
};
////
struct SlotConfiguration
{
protected:
SlotConfiguration(SlotTypeDescriptor slotType);
public:
AZ_CLASS_ALLOCATOR(SlotConfiguration, AZ::SystemAllocator, 0);
AZ_RTTI(SlotConfiguration, "{C169C86A-378F-4263-8B8D-C40D51631ECF}");
virtual ~SlotConfiguration() = default;
void SetConnectionType(ConnectionType connectionType);
const SlotDescriptor& GetSlotDescriptor() const { return m_slotDescriptor; }
AZStd::string m_name;
AZStd::string m_toolTip;
bool m_isLatent = false;
AZStd::vector<ContractDescriptor> m_contractDescs;
bool m_addUniqueSlotByNameAndType = true; // Only adds a new slot if a slot with the supplied name and SlotType does not exist on the node
// Specifies the Id the slot will use. Generally necessary only in undo/redo case with dynamically added
// slots to preserve data integrity
SlotId m_slotId;
AZStd::string m_displayGroup;
private:
SlotDescriptor m_slotDescriptor;
};
struct ExecutionSlotConfiguration
: public SlotConfiguration
{
AZ_CLASS_ALLOCATOR(ExecutionSlotConfiguration, AZ::SystemAllocator, 0);
AZ_RTTI(ExecutionSlotConfiguration, "{F2785E7D-635F-4C94-BAB2-F09F8FB2B7CF}", SlotConfiguration);
ExecutionSlotConfiguration()
: SlotConfiguration(SlotTypeDescriptor::Execution)
{
}
ExecutionSlotConfiguration(AZStd::string_view name, ConnectionType connectionType, AZStd::string_view toolTip = {})
: SlotConfiguration(SlotTypeDescriptor::Execution)
{
m_name = name;
m_toolTip = toolTip;
SetConnectionType(connectionType);
}
};
struct DataSlotConfiguration
: public SlotConfiguration
{
AZ_CLASS_ALLOCATOR(DataSlotConfiguration, AZ::SystemAllocator, 0);
AZ_RTTI(DataSlotConfiguration, "{9411A82E-EB3E-4235-9DDA-12EF6C9ECB1D}", SlotConfiguration);
DataSlotConfiguration()
: SlotConfiguration(SlotTypeDescriptor::Data)
{
}
DataSlotConfiguration(Datum&& datum);
DataSlotConfiguration(Data::Type dataType);
DataSlotConfiguration(Data::Type dataType, AZStd::string name, ConnectionType connectionType);
template<class DataType>
void SetDefaultValue(DataType defaultValue)
{
m_datum.SetAZType<DataType>();
m_datum.Set<DataType>(defaultValue);
}
template<class DataType>
void SetAZType()
{
m_datum.SetAZType<DataType>();
}
void SetType(Data::Type dataType);
void SetType(const AZ::BehaviorParameter& typeDesc);
void ConfigureDatum(Datum&& datum)
{
m_datum.ReconfigureDatumTo(AZStd::move(datum));
}
const Datum& GetDatum() const
{
return m_datum;
}
private:
Datum m_datum;
};
struct DynamicDataSlotConfiguration
: public SlotConfiguration
{
AZ_CLASS_ALLOCATOR(DynamicDataSlotConfiguration, AZ::SystemAllocator, 0);
AZ_RTTI(DynamicDataSlotConfiguration, "{64BB0D10-D776-4D28-AF33-065530A95310}", SlotConfiguration);
DynamicDataSlotConfiguration()
: SlotConfiguration(SlotTypeDescriptor::Data)
{
}
AZ::Crc32 m_dynamicGroup = AZ::Crc32();
DynamicDataType m_dynamicDataType = DynamicDataType::None;
Data::Type m_displayType = Data::Type::Invalid();
};
}
@@ -0,0 +1,29 @@
/*
* 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 <ScriptCanvas/Core/SlotMetadata.h>
#include <ScriptCanvas/Data/BehaviorContextObject.h>
namespace ScriptCanvas
{
void SlotMetadata::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<SlotMetadata>()
->Field("m_slotId", &SlotMetadata::m_slotId)
->Field("m_dataType", &SlotMetadata::m_dataType)
;
}
}
}
@@ -0,0 +1,27 @@
/*
* 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
#include <ScriptCanvas/Data/Data.h>
namespace ScriptCanvas
{
struct SlotMetadata
{
AZ_TYPE_INFO(SlotMetadata, "{315C9851-1747-4D68-9A4A-B699FA9FC754}");
AZ_CLASS_ALLOCATOR(SlotMetadata, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* reflectContext);
SlotId m_slotId;
Data::Type m_dataType;
};
}
@@ -0,0 +1,23 @@
/*
* 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
#include <AzCore/std/string/string_view.h>
namespace ScriptCanvas
{
AZ_INLINE AZStd::string_view GetInputSlotName() { return "In"; }
AZ_INLINE AZStd::string_view GetOutputSlotName() { return "Out"; }
AZ_INLINE AZStd::string_view GetSourceSlotName() { return "Source"; }
}
@@ -0,0 +1,140 @@
/*
* 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 "BehaviorContextObject.h"
#include <ScriptCanvas/Core/ScriptCanvasBus.h>
#include <ScriptCanvas/Data/DataRegistry.h>
#include <AzCore/Component/EntityBus.h>
#include <AzCore/Serialization/Utils.h>
#include <ScriptCanvas/Core/GraphScopedTypes.h>
namespace ScriptCanvas
{
void BehaviorContextObject::OnReadBegin()
{
if (!IsOwned())
{
Clear();
}
}
void BehaviorContextObject::OnWriteEnd()
{
// Id Remapping invokes this method as well, not just serializing from an ObjectStream
}
void BehaviorContextObject::Reflect(AZ::ReflectContext* reflection)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
{
serializeContext->Class<BehaviorContextObject>()
->Version(0)
->EventHandler<SerializeContextEventHandler>()
->Field("m_flags", &BehaviorContextObject::m_flags)
->Field("m_object", &BehaviorContextObject::m_object)
;
if (auto editContext = serializeContext->GetEditContext())
{
editContext->Class<BehaviorContextObject>("", "BehaviorContextObject")
->ClassElement(AZ::Edit::ClassElements::EditorData, "BehaviorContextObject")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->DataElement(AZ::Edit::UIHandlers::Default, &BehaviorContextObject::m_object, "Datum", "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, true)
;
}
}
}
void BehaviorContextObject::SerializeContextEventHandler::OnReadBegin(void* classPtr)
{
BehaviorContextObject* object = reinterpret_cast<BehaviorContextObject*>(classPtr);
object->OnReadBegin();
}
void BehaviorContextObject::SerializeContextEventHandler::OnWriteEnd(void* classPtr)
{
BehaviorContextObject* object = reinterpret_cast<BehaviorContextObject*>(classPtr);
object->OnWriteEnd();
}
BehaviorContextObjectPtr BehaviorContextObject::CloneObject(const AZ::BehaviorClass& behaviorClass)
{
if (SystemRequestBus::HasHandlers())
{
AZStd::vector<char> buffer;
{
bool wasOwned = IsOwned();
m_flags |= Flags::Owned;
AZ::IO::ByteContainerStream<AZStd::vector<char>> writeStream(&buffer);
AZ::Utils::SaveObjectToStream<BehaviorContextObject>(writeStream, AZ::DataStream::ST_BINARY, this);
if (!wasOwned)
{
m_flags &= ~Flags::Owned;
}
}
AZ::IO::ByteContainerStream<AZStd::vector<char>> readStream(&buffer);
BehaviorContextObject* newObject = CreateDefault(behaviorClass);
AZ::Utils::LoadObjectFromStreamInPlace(readStream, (*newObject));
if (newObject != nullptr)
{
SystemRequestBus::Broadcast(&SystemRequests::AddOwnedObjectReference, newObject->Get(), newObject);
return BehaviorContextObjectPtr(newObject);
}
}
return nullptr;
}
BehaviorContextObjectPtr BehaviorContextObject::Create(const AZ::BehaviorClass& behaviorClass, const void* value)
{
if (SystemRequestBus::HasHandlers())
{
BehaviorContextObject* ownedObject = value ? CreateCopy(behaviorClass, value) : CreateDefault(behaviorClass);
SystemRequestBus::Broadcast(&SystemRequests::AddOwnedObjectReference, ownedObject->Get(), ownedObject);
return BehaviorContextObjectPtr(ownedObject);
}
AZ_Assert(false, "The Script Canvas SystemRequest Bus needs to be handled by at least one class!");
return nullptr;
}
BehaviorContextObjectPtr BehaviorContextObject::CreateReference(const AZ::Uuid& typeID, void* reference)
{
const AZ::u32 referenceFlags(0);
BehaviorContextObject* ownedObject{};
SystemRequestBus::BroadcastResult(ownedObject, &SystemRequests::FindOwnedObjectReference, reference);
return ownedObject
? BehaviorContextObjectPtr(ownedObject)
: BehaviorContextObjectPtr(aznew BehaviorContextObject(reference, GetAnyTypeInfoReference(typeID), referenceFlags));
}
void BehaviorContextObject::release()
{
if (--m_referenceCount == 0)
{
SystemRequestBus::Broadcast(&SystemRequests::RemoveOwnedObjectReference, Get());
delete this;
}
}
} // namespace ScriptCanvas
@@ -0,0 +1,437 @@
/*
* 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
#include <AzCore/RTTI/AttributeReader.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Script/ScriptContextAttributes.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/any.h>
#include <AzCore/std/parallel/atomic.h>
#include <ScriptCanvas/Data/Data.h>
#include "BehaviorContextObjectPtr.h"
namespace AZ
{
class ReflectContext;
}
namespace ScriptCanvas
{
class BehaviorContextObject final
{
friend struct AZStd::IntrusivePtrCountPolicy<BehaviorContextObject>;
public:
AZ_TYPE_INFO(BehaviorContextObject, "{B735214D-5182-4536-B748-61EC83C1F007}");
AZ_CLASS_ALLOCATOR(BehaviorContextObject, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* reflection);
static BehaviorContextObjectPtr Create(const AZ::BehaviorClass& behaviorClass, const void* value = nullptr);
static BehaviorContextObjectPtr CreateDeepCopy(const AZ::BehaviorClass& behaviorClass, const BehaviorContextObject* value = nullptr);
template<typename t_Value>
AZ_INLINE static BehaviorContextObjectPtr Create(const t_Value& value, const AZ::BehaviorClass& behaviorClass);
static BehaviorContextObjectPtr CreateReference(const AZ::Uuid& typeID, void* reference = nullptr);
template<typename t_Value>
AZ_INLINE t_Value* Cast();
template<typename t_Value>
AZ_INLINE const t_Value* CastConst() const;
AZ_FORCE_INLINE const void* Get() const;
AZ_FORCE_INLINE void* Mod();
BehaviorContextObjectPtr CloneObject(const AZ::BehaviorClass& behaviorClass);
private:
using AnyTypeHandlerFunction = AZStd::any::type_info::HandleFnT;
using AnyTypeInfo = AZStd::any::type_info;
enum Flags
{
Const = 1 << 0,
Owned = 1 << 1,
Pointer = 1 << 2,
Reference = 1 << 3,
};
class SerializeContextEventHandler : public AZ::SerializeContext::IEventHandler
{
public:
/// Called right before we start reading from the instance pointed by classPtr.
void OnReadBegin(void* classPtr) override;
/// Called after we are done writing to the instance pointed by classPtr.
void OnWriteEnd(void* classPtr) override;
};
template<typename... Args>
static AZ::BehaviorObject InvokeConstructor(const AZ::BehaviorClass& behaviorClass, void* resultPtr, Args&&... args);
AZ_INLINE static BehaviorContextObject* CreateCopy(const AZ::BehaviorClass& behaviorClass, const void* value);
AZ_INLINE static BehaviorContextObject* CreateDefault(const AZ::BehaviorClass& behaviorClass);
AZ_INLINE static BehaviorContextObject* CreateDefaultBuffer(const AZ::BehaviorClass& behaviorClass);
AZ_INLINE static BehaviorContextObject* CreateDefaultHeap(const AZ::BehaviorClass& behaviorClass);
// use the SSO optimization on behavior class size ALIGNED with a placement new of behavior class create
AZ_FORCE_INLINE static AnyTypeInfo GetAnyTypeInfoObject(const AZ::BehaviorClass& behaviorClass);
AZ_FORCE_INLINE static AnyTypeInfo GetAnyTypeInfoReference(const AZ::Uuid& typeID);
AZ_FORCE_INLINE static AnyTypeHandlerFunction GetHandlerObject(const AZ::BehaviorClass& behaviorClass, bool useHeap);
AZ_FORCE_INLINE static AnyTypeHandlerFunction GetHandlerObjectBuffer(const AZ::BehaviorClass& behaviorClass);
AZ_FORCE_INLINE static AnyTypeHandlerFunction GetHandlerObjectHeap(const AZ::BehaviorClass& behaviorClass);
AZ_FORCE_INLINE static AnyTypeHandlerFunction GetHandlerReference();
AZStd::atomic_int m_referenceCount{0};
AZ::u32 m_flags{ 0 };
AZStd::any m_object;
// it is very important to track these from the moment they are created...
friend struct AZ::Serialize::InstanceFactory<BehaviorContextObject, true, false>;
friend struct AZ::AnyTypeInfoConcept<BehaviorContextObject, void>;
//...so don't use the ctors, use the Create functions...
//...the friend declarations are here for compatibility with the serialization system only
AZ_FORCE_INLINE BehaviorContextObject() = default;
BehaviorContextObject& operator=(const BehaviorContextObject&) = delete;
// copy ctor
AZ_FORCE_INLINE BehaviorContextObject(const void* source, const AnyTypeInfo& typeInfo, AZ::u32 flags);
// reference or transfer ownership ctor
AZ_FORCE_INLINE BehaviorContextObject(void* source, const AnyTypeInfo& typeInfo, AZ::u32 flags);
AZ_FORCE_INLINE void Clear();
AZ_FORCE_INLINE bool IsOwned() const;
void OnReadBegin();
void OnWriteEnd();
AZ_FORCE_INLINE void add_ref();
void release();
public:
// no copying allowed, this is here to allow compile time compatibility with storage in of BehaviorContextObjectPtr AZStd::any, only
AZ_FORCE_INLINE BehaviorContextObject(const BehaviorContextObject&)
{
AZ_Assert(false, "no copying allowed, this is here to allow storage in of BehaviorContextObjectPtr AZStd::any, only");
}
}; // class BehaviorContextObject
AZ_FORCE_INLINE BehaviorContextObject::BehaviorContextObject(const void* value, const AnyTypeInfo& typeInfo, AZ::u32 flags)
: m_referenceCount(0)
, m_flags(flags)
, m_object(value, typeInfo)
{}
AZ_FORCE_INLINE BehaviorContextObject::BehaviorContextObject(void* value, const AnyTypeInfo& typeInfo, AZ::u32 flags)
: m_referenceCount(0)
, m_flags(flags)
, m_object(AZStd::s_transfer_ownership, value, typeInfo)
{
AZ_Assert((flags & Owned) || AZStd::any_cast<void>(&m_object) == value, "Failed to store the reference in the any class");
}
template<typename t_Value>
AZ_INLINE t_Value* BehaviorContextObject::Cast()
{
return AZStd::any_cast<t_Value>(&m_object);
}
template<typename t_Value>
AZ_INLINE const t_Value* BehaviorContextObject::CastConst() const
{
return AZStd::any_cast<const t_Value>(&m_object);
}
AZ_FORCE_INLINE void BehaviorContextObject::Clear()
{
m_object.clear();
m_flags = 0;
}
template<AZStd::size_t Capacity>
bool CompareSignature(AZ::BehaviorMethod* method, const AZStd::array<AZ::Uuid, Capacity>& typeIds)
{
bool signatureMatch = method->GetNumArguments() == typeIds.size();
for (size_t index = 0; index < typeIds.size() && signatureMatch; ++index)
{
signatureMatch = method->GetArgument(index)->m_typeId == typeIds[index];
}
return signatureMatch;
}
template<size_t startIndex, typename ArrayType, typename... Args, size_t... Indices>
void UnpackParameterAtIndex(ArrayType& outArray, AZStd::index_sequence<Indices...>, Args&&... args)
{
using dummy = int[];
(void)dummy{0, ((outArray[startIndex + Indices] = AZStd::forward<Args>(args)), 0)... };
}
template<typename... Args>
AZ::BehaviorObject BehaviorContextObject::InvokeConstructor(const AZ::BehaviorClass& behaviorClass, void* resultPtr, Args&&... args)
{
// The constructor result would be stored in the first argument
AZStd::array<AZ::Uuid, 1 + sizeof...(Args)> typeIds{ {behaviorClass.m_typeId} };
UnpackParameterAtIndex<1>(typeIds, AZStd::make_index_sequence<sizeof...(Args)>(), AZ::AzTypeInfo<Args>::Uuid()...);
AZ::BehaviorMethod* invokableMethod{};
AZ::Attribute* genericConstructorAttr = FindAttribute(AZ::Script::Attributes::GenericConstructorOverride, behaviorClass.m_attributes);
if (genericConstructorAttr)
{
if (auto genericConstructorMethod = reinterpret_cast<AZ::BehaviorMethod*>(genericConstructorAttr->GetContextData()))
{
if (CompareSignature(genericConstructorMethod, typeIds))
{
invokableMethod = genericConstructorMethod;
}
}
}
// Check all constructors and see if they match all the parameters
if (!invokableMethod)
{
for (AZ::BehaviorMethod* method : behaviorClass.m_constructors)
{
if (CompareSignature(method, typeIds))
{
invokableMethod = method;
break;
}
}
}
AZ::BehaviorObject resultObj{ resultPtr, behaviorClass.m_typeId };
if (invokableMethod)
{
if (!resultObj.IsValid())
{
resultObj.m_address = behaviorClass.Allocate();
}
AZStd::array<AZ::BehaviorValueParameter, 1 + sizeof...(Args)> params{ {&resultObj} };
UnpackParameterAtIndex<1>(params, AZStd::make_index_sequence<sizeof...(Args)>(), AZStd::forward<Args>(args)...);
invokableMethod->Call(params.data(), static_cast<AZ::u32>(params.size()));
return resultObj;
}
else if (behaviorClass.m_defaultConstructor)
{
// Otherwise use the default constructor
if (!resultObj.IsValid())
{
resultObj.m_address = behaviorClass.Allocate();
}
behaviorClass.m_defaultConstructor(resultObj.m_address, nullptr);
}
return resultObj;
}
template<typename t_Value>
AZ_INLINE BehaviorContextObjectPtr BehaviorContextObject::Create(const t_Value& value, const AZ::BehaviorClass& behaviorClass)
{
AZ_Assert(azrtti_typeid<t_Value>() == behaviorClass.m_typeId, "bad call to Create, mismatch with azrttti on value and behavior class");
return Create(behaviorClass, reinterpret_cast<const void*>(&value));
}
AZ_INLINE BehaviorContextObject* BehaviorContextObject::CreateCopy(const AZ::BehaviorClass& behaviorClass, const void* value)
{
AZ_Assert(value, "invalid copy source object");
return aznew BehaviorContextObject(value, GetAnyTypeInfoObject(behaviorClass), Owned);
}
AZ_INLINE BehaviorContextObject* BehaviorContextObject::CreateDefault(const AZ::BehaviorClass& behaviorClass)
{
const bool useHeap = AZStd::GetMax(behaviorClass.m_size, behaviorClass.m_alignment) > AZStd::Internal::ANY_SBO_BUF_SIZE;
return useHeap ? CreateDefaultHeap(behaviorClass) : CreateDefaultBuffer(behaviorClass);
}
AZ_INLINE BehaviorContextObject* BehaviorContextObject::CreateDefaultBuffer(const AZ::BehaviorClass& behaviorClass)
{
AZ_ALIGN(char buffer[AZStd::Internal::ANY_SBO_BUF_SIZE], 32);
AZ::BehaviorObject object = InvokeConstructor(behaviorClass, AZStd::addressof(buffer));
auto bco = aznew BehaviorContextObject(object.m_address, GetAnyTypeInfoObject(behaviorClass), Owned);
behaviorClass.m_destructor(object.m_address, behaviorClass.m_userData);
return bco;
}
AZ_INLINE BehaviorContextObject* BehaviorContextObject::CreateDefaultHeap(const AZ::BehaviorClass& behaviorClass)
{
AZ::BehaviorObject object = InvokeConstructor(behaviorClass, nullptr);
auto bco = aznew BehaviorContextObject(object.m_address, GetAnyTypeInfoObject(behaviorClass), Owned);
return bco;
}
AZ_FORCE_INLINE const void* BehaviorContextObject::Get() const
{
return const_cast<BehaviorContextObject*>(this)->Mod();
}
AZ_FORCE_INLINE BehaviorContextObject::AnyTypeInfo BehaviorContextObject::GetAnyTypeInfoObject(const AZ::BehaviorClass& behaviorClass)
{
const bool useHeap = AZStd::GetMax(behaviorClass.m_size, behaviorClass.m_alignment) > AZStd::Internal::ANY_SBO_BUF_SIZE;
AZStd::any::type_info typeInfo;
typeInfo.m_id = behaviorClass.m_typeId;
typeInfo.m_useHeap = useHeap;
typeInfo.m_handler = GetHandlerObject(behaviorClass, useHeap);
return typeInfo;
}
AZ_FORCE_INLINE BehaviorContextObject::AnyTypeInfo BehaviorContextObject::GetAnyTypeInfoReference(const AZ::Uuid& typeID)
{
AZStd::any::type_info typeInfo;
typeInfo.m_id = typeID;
typeInfo.m_useHeap = true; // always true for references, regardless of size
typeInfo.m_handler = GetHandlerReference();
return typeInfo;
}
AZ_FORCE_INLINE BehaviorContextObject::AnyTypeHandlerFunction BehaviorContextObject::GetHandlerObject(const AZ::BehaviorClass& behaviorClass, bool useHeap)
{
return useHeap ? GetHandlerObjectHeap(behaviorClass) : GetHandlerObjectBuffer(behaviorClass);
}
AZ_FORCE_INLINE BehaviorContextObject::AnyTypeHandlerFunction BehaviorContextObject::GetHandlerObjectBuffer(const AZ::BehaviorClass& behaviorClass)
{
return [&behaviorClass](AZStd::any::Action action, AZStd::any* dest, const AZStd::any* source)
{
switch (action)
{
case AZStd::any::Action::Reserve:
{
break;
}
case AZStd::any::Action::Copy:
{
AZ_Assert(dest->get_type_info().m_id == behaviorClass.m_typeId, "invalid any destination");
behaviorClass.m_cloner(AZStd::any_cast<void>(dest), AZStd::any_cast<void>(source), behaviorClass.m_userData);
break;
}
case AZStd::any::Action::Move:
{
AZ_Assert(dest->get_type_info().m_id == behaviorClass.m_typeId, "invalid any destination");
behaviorClass.m_mover(AZStd::any_cast<void>(dest), AZStd::any_cast<void>(const_cast<AZStd::any*>(source)), behaviorClass.m_userData);
break;
}
case AZStd::any::Action::Destroy:
{
AZ_Assert(dest->get_type_info().m_id == behaviorClass.m_typeId, "invalid any destination");
behaviorClass.m_destructor(AZStd::any_cast<void>(dest), behaviorClass.m_userData);
break;
}
}
};
}
AZ_FORCE_INLINE BehaviorContextObject::AnyTypeHandlerFunction BehaviorContextObject::GetHandlerObjectHeap(const AZ::BehaviorClass& behaviorClass)
{
// If it's a value type, copy/move it around, technically, this will only happen one time on construction
// if we add on extension to the any class, we could just assert on all these operations (except copy)
return [&behaviorClass](AZStd::any::Action action, AZStd::any* dest, const AZStd::any* source)
{
switch (action)
{
case AZStd::any::Action::Reserve:
{
AZ_Assert(dest->get_type_info().m_id == behaviorClass.m_typeId, "invalid any destination");
AZ_Assert(dest->get_type_info().m_useHeap == true, "invalid heap target");
*reinterpret_cast<void**>(dest) = behaviorClass.Allocate();
break;
}
case AZStd::any::Action::Copy:
{
AZ_Assert(dest->get_type_info().m_id == behaviorClass.m_typeId, "invalid any destination");
AZ_Assert(dest->get_type_info().m_useHeap == true, "invalid heap target");
behaviorClass.m_cloner(AZStd::any_cast<void>(dest), AZStd::any_cast<void>(source), behaviorClass.m_userData);
break;
}
case AZStd::any::Action::Move:
{
AZ_Assert(dest->get_type_info().m_id == behaviorClass.m_typeId, "invalid any destination");
AZ_Assert(dest->get_type_info().m_useHeap == true, "invalid heap target");
behaviorClass.m_mover(AZStd::any_cast<void>(dest), AZStd::any_cast<void>(const_cast<AZStd::any*>(source)), behaviorClass.m_userData);
break;
}
case AZStd::any::Action::Destroy:
{
AZ_Assert(dest->get_type_info().m_id == behaviorClass.m_typeId, "invalid any destination");
AZ_Assert(dest->get_type_info().m_useHeap == true, "invalid heap target");
behaviorClass.Destroy(AZ::BehaviorObject(AZStd::any_cast<void>(dest), behaviorClass.m_typeId));
break;
}
}
};
}
AZ_FORCE_INLINE BehaviorContextObject::AnyTypeHandlerFunction BehaviorContextObject::GetHandlerReference()
{
// reference type, just move the pointer around
return [](AZStd::any::Action action, AZStd::any* dest, const AZStd::any* source)
{
switch (action)
{
case AZStd::any::Action::Reserve:
{
// No-op
break;
}
case AZStd::any::Action::Copy:
case AZStd::any::Action::Move:
{
*reinterpret_cast<void**>(dest) = AZStd::any_cast<void>(const_cast<AZStd::any*>(source));
break;
}
case AZStd::any::Action::Destroy:
{
*reinterpret_cast<void**>(dest) = nullptr;
break;
}
}
};
}
AZ_FORCE_INLINE bool BehaviorContextObject::IsOwned() const
{
return (m_flags & Flags::Owned) != 0;
}
AZ_FORCE_INLINE void* BehaviorContextObject::Mod()
{
return AZStd::any_cast<void>(&m_object);
}
AZ_FORCE_INLINE void BehaviorContextObject::add_ref()
{
++m_referenceCount;
}
} // namespace ScriptCanvas
@@ -0,0 +1,43 @@
/*
* 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 "BehaviorContextObjectPtr.h"
#include <AzCore/RTTI/ReflectContext.h>
#include "BehaviorContextObject.h"
namespace ScriptCanvas
{
void BehaviorContextObjectPtrReflect(AZ::ReflectContext* context)
{
BehaviorContextObject::Reflect(context);
auto behaviorContextObjectPtrGenericClassInfo = AZ::SerializeGenericTypeInfo<BehaviorContextObjectPtr>::GetGenericInfo();
if (!behaviorContextObjectPtrGenericClassInfo)
{
return;
}
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
behaviorContextObjectPtrGenericClassInfo->Reflect(serializeContext);
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<BehaviorContextObjectPtr>("BehaviorContextObjectPtr", "Intrusive pointer which keeps a count of ScriptCanvas references to data from the BehaviorContext")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
;
}
}
}
}
@@ -0,0 +1,28 @@
/*
* 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
#include <AzCore/RTTI/TypeInfo.h>
#include <AzCore/std/smart_ptr/intrusive_ptr.h>
namespace AZ
{
class ReflectContext;
} // namespace AZ
namespace ScriptCanvas
{
class BehaviorContextObject;
using BehaviorContextObjectPtr = AZStd::intrusive_ptr<BehaviorContextObject>;
void BehaviorContextObjectPtrReflect(AZ::ReflectContext* context);
} // namespace ScriptCanvas
@@ -0,0 +1,471 @@
/*
* 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 "Data.h"
#include <ScriptCanvas/Data/DataTrait.h>
#include <AzCore/Component/EntityBus.h>
#include <AzCore/RTTI/AttributeReader.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/Utils.h>
namespace DataCpp
{
using namespace ScriptCanvas;
using namespace ScriptCanvas::Data;
AZ_INLINE AZStd::pair<bool, Type> FromAZTypeHelper(const AZ::Uuid& type)
{
if (type.IsNull())
{
return { true, Type::Invalid() };
}
else if (IsAABB(type))
{
return { true, Type::AABB() };
}
else if (IsAssetId(type))
{
return { true, Type::AssetId() };
}
else if (IsBoolean(type))
{
return { true, Type::Boolean() };
}
else if (IsColor(type))
{
return { true, Type::Color() };
}
else if (IsCRC(type))
{
return { true, Type::CRC() };
}
else if (IsEntityID(type))
{
return { true, Type::EntityID() };
}
else if (IsNamedEntityID(type))
{
return{ true, Type::NamedEntityID() };
}
else if (IsMatrix3x3(type))
{
return { true, Type::Matrix3x3() };
}
else if (IsMatrix4x4(type))
{
return { true, Type::Matrix4x4() };
}
else if (IsNumber(type))
{
return { true, Type::Number() };
}
else if (IsOBB(type))
{
return { true, Type::OBB() };
}
else if (IsPlane(type))
{
return { true, Type::Plane() };
}
else if (IsQuaternion(type))
{
return { true, Type::Quaternion() };
}
else if (IsString(type))
{
return { true, Type::String() };
}
else if (IsTransform(type))
{
return { true, Type::Transform() };
}
else if (IsVector2(type))
{
return { true, Type::Vector2() };
}
else if (IsVector3(type))
{
return { true, Type::Vector3() };
}
else if (IsVector4(type))
{
return { true, Type::Vector4() };
}
else
{
return { false, Type::Invalid() };
}
}
AZ_INLINE AZStd::pair<bool, Type> FromBehaviorContextTypeHelper(const AZ::Uuid& type)
{
if (type.IsNull())
{
return { true, Type::Invalid() };
}
else if (IsBoolean(type))
{
return { true, Type::Boolean() };
}
else if (IsEntityID(type))
{
return { true, Type::EntityID() };
}
else if (IsNamedEntityID(type))
{
return{ true, Type::NamedEntityID() };
}
else if (IsNumber(type))
{
return { true, Type::Number() };
}
else if (IsString(type))
{
return { true, Type::String() };
}
else
{
return { false, Type::Invalid() };
}
}
AZ_INLINE bool IsSupportedBehaviorContextObject(const AZ::Uuid& typeID)
{
return AZ::BehaviorContextHelper::GetClass(typeID) != nullptr;
}
AZ_INLINE const char* GetRawBehaviorContextName(const AZ::Uuid& typeID)
{
AZ::BehaviorContext* behaviorContext(nullptr);
AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationRequests::GetBehaviorContext);
if (!behaviorContext)
{
AZ_Assert(behaviorContext, "A behavior context is required!");
return "Invalid BehaviorContext::Class name";
}
if (const AZ::BehaviorClass* behaviorClass = AZ::BehaviorContextHelper::GetClass(typeID))
{
return behaviorClass->m_name.data();
}
return "Invalid BehaviorContext::Class name";
}
}
namespace ScriptCanvas
{
namespace Data
{
Type FromAZType(const AZ::Uuid& type)
{
AZStd::pair<bool, Type> help = DataCpp::FromAZTypeHelper(type);
return help.first ? help.second : Type::BehaviorContextObject(type);
}
Type FromAZTypeChecked(const AZ::Uuid& type)
{
AZStd::pair<bool, Type> help = DataCpp::FromAZTypeHelper(type);
return help.first
? help.second
: DataCpp::IsSupportedBehaviorContextObject(type)
? Type::BehaviorContextObject(type)
: Type::Invalid();
}
AZStd::string GetBehaviorClassName(const AZ::Uuid& typeID)
{
AZ::BehaviorContext* behaviorContext(nullptr);
AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationRequests::GetBehaviorContext);
if (!behaviorContext)
{
AZ_Error("Behavior Context", false, "A behavior context is required!");
return "Invalid BehaviorContext::Class name";
}
if (AZ::Utils::IsGenericContainerType(typeID))
{
if (AZ::Utils::IsSetContainerType(typeID))
{
return "Set";
}
else if (AZ::Utils::IsMapContainerType(typeID))
{
return "Map";
}
// Special casing out the fixed size vectors/arrays.
// Will need a more in depth way of generating these names long term I think.
else if (typeID == AZ::GetGenericClassInfoArrayTypeId()
|| typeID == AZ::GetGenericClassInfoFixedVectorTypeId())
{
return "Fixed Size Array";
}
else if (AZ::Utils::IsVectorContainerType(typeID))
{
return "Array";
}
else
{
return "Unknown Container";
}
}
else
{
if (const AZ::BehaviorClass* behaviorClass = AZ::BehaviorContextHelper::GetClass(typeID))
{
if (AZ::Attribute* prettyNameAttribute = AZ::FindAttribute(AZ::ScriptCanvasAttributes::PrettyName, behaviorClass->m_attributes))
{
AZ::AttributeReader operatorAttrReader(nullptr, prettyNameAttribute);
AZStd::string prettyName;
if (operatorAttrReader.Read<AZStd::string>(prettyName, *behaviorContext))
{
return prettyName;
}
}
return behaviorClass->m_name;
}
}
return "Invalid BehaviorContext::Class name";
}
AZStd::string GetName(const Type& type)
{
switch (type.GetType())
{
case eType::AABB:
return eTraits<eType::AABB>::GetName();
case eType::AssetId:
return eTraits<eType::AssetId>::GetName();
case eType::BehaviorContextObject:
return GetBehaviorClassName(type.GetAZType());
case eType::Boolean:
return eTraits<eType::Boolean>::GetName();
case eType::Color:
return eTraits<eType::Color>::GetName();
case eType::CRC:
return eTraits<eType::CRC>::GetName();
case eType::EntityID:
return eTraits<eType::EntityID>::GetName();
case eType::NamedEntityID:
return eTraits<eType::NamedEntityID>::GetName();
case eType::Invalid:
return "Invalid";
case eType::Matrix3x3:
return eTraits<eType::Matrix3x3>::GetName();
case eType::Matrix4x4:
return eTraits<eType::Matrix4x4>::GetName();
case eType::Number:
return eTraits<eType::Number>::GetName();
case eType::OBB:
return eTraits<eType::OBB>::GetName();
case eType::Plane:
return eTraits<eType::Plane>::GetName();
case eType::Quaternion:
return eTraits<eType::Quaternion>::GetName();
case eType::String:
return eTraits<eType::String>::GetName();
case eType::Transform:
return eTraits<eType::Transform>::GetName();
case eType::Vector2:
return eTraits<eType::Vector2>::GetName();
case eType::Vector3:
return eTraits<eType::Vector3>::GetName();
case eType::Vector4:
return eTraits<eType::Vector4>::GetName();
default:
AZ_Assert(false, "Invalid type!");
return "Error: invalid type";
}
}
const char* GetBehaviorContextName(const AZ::Uuid& azType)
{
return GetBehaviorContextName(FromAZType(azType));
}
const char* GetBehaviorContextName(const Type& type)
{
switch (type.GetType())
{
case eType::Boolean:
return "Boolean";
case eType::EntityID:
return "EntityId";
case eType::Invalid:
return "Invalid";
case eType::Number:
return "Number";
case eType::String:
return "String";
case eType::AABB:
case eType::AssetId:
case eType::BehaviorContextObject:
case eType::Color:
case eType::CRC:
case eType::Matrix3x3:
case eType::Matrix4x4:
case eType::OBB:
case eType::Plane:
case eType::Quaternion:
case eType::Transform:
case eType::Vector3:
case eType::Vector2:
case eType::Vector4:
default:
return DataCpp::GetRawBehaviorContextName(ToAZType(type));
}
}
bool IsOutcomeType(const AZ::Uuid& type)
{
return AZ::Utils::IsOutcomeType(type);
}
bool IsOutcomeType(const Type& type)
{
return AZ::Utils::IsOutcomeType(ToAZType(type));
}
bool IsVectorContainerType(const AZ::Uuid& type)
{
return AZ::Utils::IsVectorContainerType(type);
}
bool IsVectorContainerType(const Type& type)
{
return AZ::Utils::IsVectorContainerType(ToAZType(type));
}
bool IsSetContainerType(const AZ::Uuid& type)
{
return AZ::Utils::IsSetContainerType(type);
}
bool IsSetContainerType(const Type& type)
{
return AZ::Utils::IsSetContainerType(ToAZType(type));
}
bool IsMapContainerType(const AZ::Uuid& type)
{
return AZ::Utils::IsMapContainerType(type);
}
bool IsMapContainerType(const Type& type)
{
return AZ::Utils::IsMapContainerType(ToAZType(type));
}
bool IsContainerType(const AZ::Uuid& type)
{
return AZ::Utils::IsContainerType(type);
}
bool IsContainerType(const Type& type)
{
return AZ::Utils::IsContainerType(ToAZType(type));
}
AZStd::vector<AZ::Uuid> GetContainedTypes(const AZ::Uuid& type)
{
return AZ::Utils::GetContainedTypes(type);
}
AZStd::vector<Type> GetContainedTypes(const Type& type)
{
AZStd::vector<Type> types;
AZ::SerializeContext* serializeContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
if (serializeContext)
{
AZ::GenericClassInfo* classInfo = serializeContext->FindGenericClassInfo(ToAZType(type));
if (classInfo)
{
for (int i = 0; i < classInfo->GetNumTemplatedArguments(); ++i)
{
types.push_back(FromAZType(classInfo->GetTemplatedTypeId(i)));
}
}
}
return types;
}
AZStd::pair<AZ::Uuid, AZ::Uuid> GetOutcomeTypes(const AZ::Uuid& type)
{
return AZ::Utils::GetOutcomeTypes(type);
}
AZStd::pair<Type, Type> GetOutcomeTypes(const Type& type)
{
AZStd::pair<AZ::Uuid, AZ::Uuid> azOutcomeTypes(GetOutcomeTypes(ToAZType(type)));
return AZStd::make_pair(FromAZType(azOutcomeTypes.first), FromAZType(azOutcomeTypes.second));
}
void Type::Reflect(AZ::ReflectContext* reflection)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
{
serializeContext->Class<Type>()
->Version(2)
->Field("m_type", &Type::m_type)
->Field("m_azType", &Type::m_azType)
;
}
}
bool Type::operator==(const Type& other) const
{
return IS_EXACTLY_A(other);
}
bool Type::operator!=(const Type& other) const
{
return !((*this) == other);
}
}
}
@@ -0,0 +1,800 @@
/*
* 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
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Component/EntityId.h>
#include <AzCore/Math/Aabb.h>
#include <AzCore/Math/Color.h>
#include <AzCore/Math/Crc.h>
#include <AzCore/Math/Matrix3x3.h>
#include <AzCore/Math/Matrix4x4.h>
#include <AzCore/Math/Obb.h>
#include <AzCore/Math/Plane.h>
#include <AzCore/Math/Quaternion.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/Math/Uuid.h>
#include <AzCore/Math/Vector2.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/Math/Vector4.h>
#include <AzCore/RTTI/TypeInfo.h>
#include <AzCore/std/string/string.h>
#include <ScriptCanvas/Core/Core.h>
namespace AZ
{
class ReflectContext;
}
namespace ScriptCanvas
{
namespace Data
{
//////////////////////////////////////////////////////////////////////////
// type interface
//////////////////////////////////////////////////////////////////////////
/// \note CHANGING THE ORDER OR NUMBER OF VALUES IN THIS LIST ALMOST CERTAINLY INVALIDATES PREVIOUS DATA
enum class eType : AZ::u32
{
Boolean,
EntityID,
Invalid,
Number,
BehaviorContextObject,
String,
Quaternion,
Transform,
Vector3,
Vector2,
Vector4,
AABB,
Color,
CRC,
Matrix3x3,
Matrix4x4,
OBB,
Plane,
NamedEntityID,
// Function,
// List,
AssetId,
};
using AABBType = AZ::Aabb;
using AssetIdType = AZ::Data::AssetId;
using BooleanType = bool;
using CRCType = AZ::Crc32;
using ColorType = AZ::Color;
using EntityIDType = AZ::EntityId;
using NamedEntityIDType = AZ::NamedEntityId;
using Matrix3x3Type = AZ::Matrix3x3;
using Matrix4x4Type = AZ::Matrix4x4;
using NumberType = double;
using OBBType = AZ::Obb;
using PlaneType = AZ::Plane;
using QuaternionType = AZ::Quaternion;
using StringType = AZStd::string;
using TransformType = AZ::Transform;
using Vector2Type = AZ::Vector2;
using Vector3Type = AZ::Vector3;
using Vector4Type = AZ::Vector4;
class Type final
{
public:
AZ_TYPE_INFO(Type, "{0EADF8F5-8AB8-42E9-9C50-F5C78255C817}");
static void Reflect(AZ::ReflectContext* reflection);
static Type AABB();
static Type AssetId();
static Type BehaviorContextObject(const AZ::Uuid& aztype);
static Type Boolean();
static Type Color();
static Type CRC();
static Type EntityID();
static Type NamedEntityID();
static Type Invalid();
static Type Matrix3x3();
static Type Matrix4x4();
static Type Number();
static Type OBB();
static Type Plane();
static Type Quaternion();
static Type String();
static Type Transform();
static Type Vector2();
static Type Vector3();
static Type Vector4();
// the default ctr produces the invalid type, and is only here to help the compiler
Type();
AZ::Uuid GetAZType() const;
eType GetType() const;
bool IsValid() const;
explicit operator bool() const;
bool operator!() const;
bool operator==(const Type& other) const;
bool operator!=(const Type& other) const;
// returns true if this type is, or is derived from the other type
// \todo support polymorphism
AZ_FORCE_INLINE bool IS_A(const Type& other) const;
AZ_FORCE_INLINE bool IS_EXACTLY_A(const Type& other) const;
AZ_FORCE_INLINE bool IsConvertibleFrom(const AZ::Uuid& target) const;
AZ_FORCE_INLINE bool IsConvertibleFrom(const Type& target) const;
AZ_FORCE_INLINE bool IsConvertibleTo(const AZ::Uuid& target) const;
AZ_FORCE_INLINE bool IsConvertibleTo(const Type& target) const;
Type& operator=(const Type& source) = default;
private:
eType m_type;
AZ::Uuid m_azType;
explicit Type(eType type);
// for BehaviorContextObjects specifically
explicit Type(const AZ::Uuid& aztype);
}; // class Type
/**
* assumes that azType is a valid script canvas type of some kind, asserts if not
* favors native ScriptCanvas types over BehaviorContext class types with the corresponding AZ type id
*/
Type FromAZType(const AZ::Uuid& aztype);
// if azType is not a valid script canvas type of some kind, returns invalid, NOT for use at run-time
Type FromAZTypeChecked(const AZ::Uuid& aztype);
template<typename T>
Type FromAZType();
// returns the most raw name for the type
const char* GetBehaviorContextName(const AZ::Uuid& azType);
const char* GetBehaviorContextName(const Type& type);
// returns a possibly prettier name for the type
AZStd::string GetBehaviorClassName(const AZ::Uuid& typeID);
// returns a possibly prettier name for the type
AZStd::string GetName(const Type& type);
// returns true if candidate is, or is derived from reference
// todo support polymorphism
bool IS_A(const Type& candidate, const Type& reference);
bool IS_EXACTLY_A(const Type& candidate, const Type& reference);
bool IsConvertible(const Type& source, const AZ::Uuid& target);
bool IsConvertible(const Type& source, const Type& target);
bool IsAutoBoxedType(const Type& type);
bool IsValueType(const Type& type);
bool IsVectorType(const AZ::Uuid& type);
bool IsVectorType(const Type& type);
AZ::Uuid ToAZType(const Type& type);
bool IsContainerType(const AZ::Uuid& type);
bool IsContainerType(const Type& type);
bool IsMapContainerType(const AZ::Uuid& type);
bool IsMapContainerType(const Type& type);
bool IsOutcomeType(const AZ::Uuid& type);
bool IsOutcomeType(const Type& type);
bool IsSetContainerType(const AZ::Uuid& type);
bool IsSetContainerType(const Type& type);
bool IsVectorContainerType(const AZ::Uuid& type);
bool IsVectorContainerType(const Type& type);
AZStd::vector<AZ::Uuid> GetContainedTypes(const AZ::Uuid& type);
AZStd::vector<Type> GetContainedTypes(const Type& type);
AZStd::pair<AZ::Uuid, AZ::Uuid> GetOutcomeTypes(const AZ::Uuid& type);
AZStd::pair<Type, Type> GetOutcomeTypes(const Type& type);
bool IsAABB(const AZ::Uuid& type);
bool IsAABB(const Type& type);
bool IsAssetId(const AZ::Uuid& type);
bool IsAssetId(const Type& type);
bool IsBoolean(const AZ::Uuid& type);
bool IsBoolean(const Type& type);
bool IsColor(const AZ::Uuid& type);
bool IsColor(const Type& type);
bool IsCRC(const AZ::Uuid& type);
bool IsCRC(const Type& type);
bool IsEntityID(const AZ::Uuid& type);
bool IsEntityID(const Type& type);
bool IsNamedEntityID(const AZ::Uuid& type);
bool IsNamedEntityID(const Type& type);
bool IsNumber(const AZ::Uuid& type);
bool IsNumber(const Type& type);
bool IsMatrix3x3(const AZ::Uuid& type);
bool IsMatrix3x3(const Type& type);
bool IsMatrix4x4(const AZ::Uuid& type);
bool IsMatrix4x4(const Type& type);
bool IsOBB(const AZ::Uuid& type);
bool IsOBB(const Type& type);
bool IsPlane(const AZ::Uuid& type);
bool IsPlane(const Type& type);
bool IsQuaternion(const AZ::Uuid& type);
bool IsQuaternion(const Type& type);
bool IsString(const AZ::Uuid& type);
bool IsString(const Type& type);
bool IsTransform(const AZ::Uuid& type);
bool IsTransform(const Type& type);
bool IsVector2(const AZ::Uuid& type);
bool IsVector2(const Type& type);
bool IsVector3(const AZ::Uuid& type);
bool IsVector3(const Type& type);
bool IsVector4(const AZ::Uuid& type);
bool IsVector4(const Type& type);
//////////////////////////////////////////////////////////////////////////
// type implementation
//////////////////////////////////////////////////////////////////////////
template<typename T>
AZ_INLINE Type FromAZType()
{
return FromAZType(azrtti_typeid<T>());
}
AZ_INLINE bool IsAABB(const AZ::Uuid& type)
{
return type == azrtti_typeid<AABBType>();
}
AZ_INLINE bool IsAABB(const Type& type)
{
return type.GetType() == eType::AABB;
}
AZ_INLINE bool IsAssetId(const AZ::Uuid& type)
{
return type == azrtti_typeid<AssetIdType>();
}
AZ_INLINE bool IsAssetId(const Type& type)
{
return type.GetType() == eType::AssetId;
}
AZ_INLINE bool IsBoolean(const AZ::Uuid& type)
{
return type == azrtti_typeid<bool>();
}
AZ_INLINE bool IsBoolean(const Type& type)
{
return type.GetType() == eType::Boolean;
}
AZ_INLINE bool IsColor(const AZ::Uuid& type)
{
return type == azrtti_typeid<ColorType>();
}
AZ_INLINE bool IsColor(const Type& type)
{
return type.GetType() == eType::Color;
}
AZ_INLINE bool IsCRC(const AZ::Uuid& type)
{
return type == azrtti_typeid<CRCType>();
}
AZ_INLINE bool IsCRC(const Type& type)
{
return type.GetType() == eType::CRC;
}
AZ_INLINE bool IsEntityID(const AZ::Uuid& type)
{
return type == azrtti_typeid<AZ::EntityId>();
}
AZ_INLINE bool IsEntityID(const Type& type)
{
return type.GetType() == eType::EntityID;
}
AZ_INLINE bool IsNamedEntityID(const AZ::Uuid& type)
{
return type == azrtti_typeid<AZ::NamedEntityId>();
}
AZ_INLINE bool IsNamedEntityID(const Type& type)
{
return type.GetType() == eType::NamedEntityID;
}
AZ_INLINE bool IsMatrix3x3(const AZ::Uuid& type)
{
return type == azrtti_typeid<AZ::Matrix3x3>();
}
AZ_INLINE bool IsMatrix3x3(const Type& type)
{
return type.GetType() == eType::Matrix3x3;
}
AZ_INLINE bool IsMatrix4x4(const AZ::Uuid& type)
{
return type == azrtti_typeid<AZ::Matrix4x4>();
}
AZ_INLINE bool IsMatrix4x4(const Type& type)
{
return type.GetType() == eType::Matrix4x4;
}
AZ_INLINE bool IsNumber(const AZ::Uuid& type)
{
return type == azrtti_typeid<AZ::s8>()
|| type == azrtti_typeid<AZ::s16>()
|| type == azrtti_typeid<AZ::s32>()
|| type == azrtti_typeid<AZ::s64>()
|| type == azrtti_typeid<AZ::u8>()
|| type == azrtti_typeid<AZ::u16>()
|| type == azrtti_typeid<AZ::u32>()
|| type == azrtti_typeid<AZ::u64>()
|| type == azrtti_typeid<unsigned long>()
|| type == azrtti_typeid<float>()
|| type == azrtti_typeid<double>();
}
AZ_INLINE bool IsNumber(const Type& type)
{
return type.GetType() == eType::Number;
}
AZ_INLINE bool IsOBB(const AZ::Uuid& type)
{
return type == azrtti_typeid<OBBType>();
}
AZ_INLINE bool IsOBB(const Type& type)
{
return type.GetType() == eType::OBB;
}
AZ_INLINE bool IsPlane(const AZ::Uuid& type)
{
return type == azrtti_typeid<PlaneType>();
}
AZ_INLINE bool IsPlane(const Type& type)
{
return type.GetType() == eType::Plane;
}
AZ_INLINE bool IsQuaternion(const AZ::Uuid& type)
{
return type == azrtti_typeid<QuaternionType>();
}
AZ_INLINE bool IsQuaternion(const Type& type)
{
return type.GetType() == eType::Quaternion;
}
AZ_INLINE bool IsString(const AZ::Uuid& type)
{
return type == azrtti_typeid<StringType>();
}
AZ_INLINE bool IsString(const Type& type)
{
return type.GetType() == eType::String;
}
AZ_INLINE bool IsTransform(const AZ::Uuid& type)
{
return type == azrtti_typeid<TransformType>();
}
AZ_INLINE bool IsTransform(const Type& type)
{
return type.GetType() == eType::Transform;
}
AZ_INLINE bool IsVector3(const AZ::Uuid& type)
{
return type == azrtti_typeid<AZ::Vector3>();
}
AZ_INLINE bool IsVector2(const AZ::Uuid& type)
{
return type == azrtti_typeid<AZ::Vector2>();
}
AZ_INLINE bool IsVector4(const AZ::Uuid& type)
{
return type == azrtti_typeid<AZ::Vector4>();
}
AZ_INLINE bool IsVector3(const Type& type)
{
return type.GetType() == eType::Vector3;
}
AZ_INLINE bool IsVector2(const Type& type)
{
return type.GetType() == eType::Vector2;
}
AZ_INLINE bool IsVector4(const Type& type)
{
return type.GetType() == eType::Vector4;
}
AZ_INLINE AZ::Uuid ToAZType(eType type)
{
switch (type)
{
case eType::AABB:
return azrtti_typeid<AABBType>();
case eType::AssetId:
return azrtti_typeid<AssetIdType>();
case eType::Boolean:
return azrtti_typeid<bool>();
case eType::Color:
return azrtti_typeid<ColorType>();
case eType::CRC:
return azrtti_typeid<CRCType>();
case eType::EntityID:
return azrtti_typeid<AZ::EntityId>();
case eType::NamedEntityID:
return azrtti_typeid<AZ::NamedEntityId>();
case eType::Invalid:
return AZ::Uuid::CreateNull();
case eType::Matrix3x3:
return azrtti_typeid<AZ::Matrix3x3>();
case eType::Matrix4x4:
return azrtti_typeid<AZ::Matrix4x4>();
case eType::Number:
return azrtti_typeid<NumberType>();
case eType::OBB:
return azrtti_typeid<OBBType>();
case eType::Plane:
return azrtti_typeid<PlaneType>();
case eType::Quaternion:
return azrtti_typeid<QuaternionType>();
case eType::String:
return azrtti_typeid<StringType>();
case eType::Transform:
return azrtti_typeid<TransformType>();
case eType::Vector2:
return azrtti_typeid<AZ::Vector2>();
case eType::Vector3:
return azrtti_typeid<AZ::Vector3>();
case eType::Vector4:
return azrtti_typeid<AZ::Vector4>();
default:
AZ_Assert(false, "Invalid type!");
// check for behavior context support
return AZ::Uuid::CreateNull();
}
}
AZ_INLINE AZ::Uuid ToAZType(const Type& type)
{
eType typeEnum = type.GetType();
if (typeEnum == eType::BehaviorContextObject)
{
return type.GetAZType();
}
return ToAZType(typeEnum);
}
AZ_INLINE bool IsVectorType(const AZ::Uuid& type)
{
return type == azrtti_typeid<AZ::Vector3>()
|| type == azrtti_typeid<AZ::Vector2>()
|| type == azrtti_typeid<AZ::Vector4>();
}
AZ_INLINE bool IsVectorType(const Type& type)
{
static const AZ::u32 s_vectorTypes =
{
1 << static_cast<AZ::u32>(eType::Vector3)
| 1 << static_cast<AZ::u32>(eType::Vector2)
| 1 << static_cast<AZ::u32>(eType::Vector4)
};
return ((1 << static_cast<AZ::u32>(type.GetType())) & s_vectorTypes) != 0;
}
AZ_INLINE bool IsAutoBoxedType(const Type& type)
{
static const AZ::u32 s_autoBoxedTypes =
{
1 << static_cast<AZ::u32>(eType::AABB)
| 1 << static_cast<AZ::u32>(eType::Color)
| 1 << static_cast<AZ::u32>(eType::CRC)
| 1 << static_cast<AZ::u32>(eType::Matrix3x3)
| 1 << static_cast<AZ::u32>(eType::Matrix4x4)
| 1 << static_cast<AZ::u32>(eType::OBB)
| 1 << static_cast<AZ::u32>(eType::Quaternion)
| 1 << static_cast<AZ::u32>(eType::Transform)
| 1 << static_cast<AZ::u32>(eType::Vector3)
| 1 << static_cast<AZ::u32>(eType::Vector2)
| 1 << static_cast<AZ::u32>(eType::Vector4)
};
return ((1 << static_cast<AZ::u32>(type.GetType())) & s_autoBoxedTypes) != 0;
}
AZ_INLINE bool IsValueType(const Type& type)
{
return type.GetType() != eType::BehaviorContextObject;
}
AZ_FORCE_INLINE Type::Type()
: m_type(eType::Invalid)
, m_azType(AZ::Uuid::CreateNull())
{}
AZ_FORCE_INLINE Type::Type(eType type)
: m_type(type)
, m_azType(AZ::Uuid::CreateNull())
{}
AZ_FORCE_INLINE Type::Type(const AZ::Uuid& aztype)
: m_type(eType::BehaviorContextObject)
, m_azType(aztype)
{
AZ_Error("ScriptCanvas", !aztype.IsNull(), "no invalid aztypes allowed");
}
AZ_FORCE_INLINE Type Type::AABB()
{
return Type(eType::AABB);
}
AZ_FORCE_INLINE Type Type::AssetId()
{
return Type(eType::AssetId);
}
AZ_FORCE_INLINE Type Type::BehaviorContextObject(const AZ::Uuid& aztype)
{
return Type(aztype);
}
AZ_FORCE_INLINE Type Type::Boolean()
{
return Type(eType::Boolean);
}
AZ_FORCE_INLINE Type Type::Color()
{
return Type(eType::Color);
}
AZ_FORCE_INLINE Type Type::CRC()
{
return Type(eType::CRC);
}
AZ_FORCE_INLINE Type Type::EntityID()
{
return Type(eType::EntityID);
}
AZ_FORCE_INLINE Type Type::NamedEntityID()
{
return Type(eType::NamedEntityID);
}
AZ_FORCE_INLINE AZ::Uuid Type::GetAZType() const
{
if (m_type == eType::BehaviorContextObject)
{
return m_azType;
}
else
{
return ScriptCanvas::Data::ToAZType((*this));
}
}
AZ_FORCE_INLINE eType Type::GetType() const
{
return m_type;
}
AZ_FORCE_INLINE Type Type::Invalid()
{
return Type();
}
AZ_FORCE_INLINE bool IS_A(const Type& candidate, const Type& reference)
{
return candidate.IS_A(reference);
}
AZ_FORCE_INLINE bool IS_EXACTLY_A(const Type& candidate, const Type& reference)
{
return candidate.IS_EXACTLY_A(reference);
}
AZ_FORCE_INLINE bool IsConvertible(const Type& source, const AZ::Uuid& target)
{
return source.IsConvertibleTo(target);
}
AZ_FORCE_INLINE bool IsConvertible(const Type& source, const Type& target)
{
return source.IsConvertibleTo(target);
}
AZ_FORCE_INLINE bool Type::IsConvertibleFrom(const AZ::Uuid& target) const
{
return FromAZType(target).IsConvertibleTo(*this);
}
AZ_FORCE_INLINE bool Type::IsConvertibleFrom(const Type& target) const
{
return target.IsConvertibleTo(*this);
}
AZ_FORCE_INLINE bool Type::IsConvertibleTo(const AZ::Uuid& target) const
{
return IsConvertibleTo(FromAZType(target));
}
AZ_FORCE_INLINE bool Type::IsConvertibleTo(const Type& target) const
{
AZ_Assert(!IS_A(target), "Don't mix concepts, it is too dangerous.");
if (GetType() == eType::BehaviorContextObject)
{
return target.GetType() != eType::BehaviorContextObject && target.IsConvertibleTo(*this);
}
if (target.GetType() == eType::BehaviorContextObject)
{
return IS_A(FromAZType(target.GetAZType()));
}
switch (GetType())
{
case eType::Vector3:
case eType::Vector2:
case eType::Vector4:
return IsVectorType(target) || (target.GetType() == eType::BehaviorContextObject && IsVectorType(target.GetAZType()));
default:
return false;
}
}
AZ_FORCE_INLINE bool Type::IS_A(const Type& other) const
{
// \todo support polymorphism
return IS_EXACTLY_A(other);
}
AZ_FORCE_INLINE bool Type::IS_EXACTLY_A(const Type& other) const
{
return m_type == other.m_type && m_azType == other.m_azType;
}
AZ_FORCE_INLINE bool Type::IsValid() const
{
return m_type != eType::Invalid;
}
AZ_FORCE_INLINE Type Type::Matrix3x3()
{
return Type(eType::Matrix3x3);
}
AZ_FORCE_INLINE Type Type::Matrix4x4()
{
return Type(eType::Matrix4x4);
}
AZ_FORCE_INLINE Type Type::Number()
{
return Type(eType::Number);
}
AZ_FORCE_INLINE Type Type::OBB()
{
return Type(eType::OBB);
}
AZ_FORCE_INLINE Type::operator bool() const
{
return m_type != eType::Invalid;
}
AZ_FORCE_INLINE bool Type::operator!() const
{
return m_type == eType::Invalid;
}
AZ_FORCE_INLINE Type Type::Plane()
{
return Type(eType::Plane);
}
AZ_FORCE_INLINE Type Type::Quaternion()
{
return Type(eType::Quaternion);
}
AZ_FORCE_INLINE Type Type::String()
{
return Type(eType::String);
}
AZ_FORCE_INLINE Type Type::Transform()
{
return Type(eType::Transform);
}
AZ_FORCE_INLINE Type Type::Vector3()
{
return Type(eType::Vector3);
}
AZ_FORCE_INLINE Type Type::Vector2()
{
return Type(eType::Vector2);
}
AZ_FORCE_INLINE Type Type::Vector4()
{
return Type(eType::Vector4);
}
} // namespace Data
} // namespace ScriptCanvas
namespace AZStd
{
template<>
struct hash<ScriptCanvas::Data::Type>
{
size_t operator()(const ScriptCanvas::Data::Type& ref) const
{
size_t seed = 0U;
hash_combine(seed, ref.GetType());
hash_combine(seed, ScriptCanvas::Data::ToAZType(ref));
return seed;
}
};
}
@@ -0,0 +1,51 @@
/*
* 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
///< these are used to ease OnDemandReflection for AZStd::types to ScriptCanvas
#define SCRIPT_CANVAS_PER_DATA_TYPE(MACRO)\
MACRO(Boolean)\
MACRO(CRC)\
MACRO(EntityID)\
MACRO(Number)\
MACRO(String)\
MACRO(AABB)\
MACRO(Color)\
MACRO(Matrix3x3)\
MACRO(Matrix4x4)\
MACRO(OBB)\
MACRO(Plane)\
MACRO(Quaternion)\
MACRO(Transform)\
MACRO(Vector2)\
MACRO(Vector3)\
MACRO(Vector4)
#define SCRIPT_CANVAS_PER_DATA_TYPE_1(MACRO, EXPOSE_TYPE)\
MACRO(Boolean, EXPOSE_TYPE)\
MACRO(CRC, EXPOSE_TYPE)\
MACRO(EntityID, EXPOSE_TYPE)\
MACRO(Number, EXPOSE_TYPE)\
MACRO(String, EXPOSE_TYPE)\
MACRO(AABB, EXPOSE_TYPE)\
MACRO(Color, EXPOSE_TYPE)\
MACRO(Matrix3x3, EXPOSE_TYPE)\
MACRO(Matrix4x4, EXPOSE_TYPE)\
MACRO(OBB, EXPOSE_TYPE)\
MACRO(Plane, EXPOSE_TYPE)\
MACRO(Quaternion, EXPOSE_TYPE)\
MACRO(Transform, EXPOSE_TYPE)\
MACRO(Vector2, EXPOSE_TYPE)\
MACRO(Vector3, EXPOSE_TYPE)\
MACRO(Vector4, EXPOSE_TYPE)
@@ -0,0 +1,128 @@
/*
* 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 <ScriptCanvas/Data/DataRegistry.h>
namespace ScriptCanvas
{
static AZ::EnvironmentVariable<DataRegistry> s_dataRegistry;
static void RegisterSCTypeTraits(DataRegistry& dataRegistry);
void InitDataRegistry()
{
s_dataRegistry = AZ::Environment::CreateVariable<DataRegistry>(s_dataRegistryName);
RegisterSCTypeTraits(*s_dataRegistry);
}
void ResetDataRegistry()
{
s_dataRegistry.Reset();
}
AZ::EnvironmentVariable<DataRegistry> GetDataRegistry()
{
return AZ::Environment::FindVariable<DataRegistry>(s_dataRegistryName);
}
void RegisterSCTypeTraits(DataRegistry& dataRegistry)
{
auto it = dataRegistry.m_typeIdTraitMap.emplace(Data::eType::Boolean, Data::MakeTypeErasedTraits<Data::eType::Boolean>());
AZ_Error("Script Canvas", it.second, "Cannot register a second Trait struct with the same ScriptCanvas type(%u)", it.first->first);
dataRegistry.m_creatableTypes.insert(it.first->second.m_dataTraits.GetSCType());
it = dataRegistry.m_typeIdTraitMap.emplace(Data::eType::EntityID, Data::MakeTypeErasedTraits<Data::eType::EntityID>());
AZ_Error("Script Canvas", it.second, "Cannot register a second Trait struct with the same ScriptCanvas type(%u)", it.first->first);
dataRegistry.m_creatableTypes.insert(it.first->second.m_dataTraits.GetSCType());
it = dataRegistry.m_typeIdTraitMap.emplace(Data::eType::Number, Data::MakeTypeErasedTraits<Data::eType::Number>());
AZ_Error("Script Canvas", it.second, "Cannot register a second Trait struct with the same ScriptCanvas type(%u)", it.first->first);
dataRegistry.m_creatableTypes.insert(it.first->second.m_dataTraits.GetSCType());
it = dataRegistry.m_typeIdTraitMap.emplace(Data::eType::String, Data::MakeTypeErasedTraits<Data::eType::String>());
AZ_Error("Script Canvas", it.second, "Cannot register a second Trait struct with the same ScriptCanvas type(%u)", it.first->first);
dataRegistry.m_creatableTypes.insert(it.first->second.m_dataTraits.GetSCType());
it = dataRegistry.m_typeIdTraitMap.emplace(Data::eType::Quaternion, Data::MakeTypeErasedTraits<Data::eType::Quaternion>());
AZ_Error("Script Canvas", it.second, "Cannot register a second Trait struct with the same ScriptCanvas type(%u)", it.first->first);
dataRegistry.m_creatableTypes.insert(it.first->second.m_dataTraits.GetSCType());
it = dataRegistry.m_typeIdTraitMap.emplace(Data::eType::Transform, Data::MakeTypeErasedTraits<Data::eType::Transform>());
AZ_Error("Script Canvas", it.second, "Cannot register a second Trait struct with the same ScriptCanvas type(%u)", it.first->first);
dataRegistry.m_creatableTypes.insert(it.first->second.m_dataTraits.GetSCType());
it = dataRegistry.m_typeIdTraitMap.emplace(Data::eType::Vector2, Data::MakeTypeErasedTraits<Data::eType::Vector2>());
AZ_Error("Script Canvas", it.second, "Cannot register a second Trait struct with the same ScriptCanvas type(%u)", it.first->first);
dataRegistry.m_creatableTypes.insert(it.first->second.m_dataTraits.GetSCType());
it = dataRegistry.m_typeIdTraitMap.emplace(Data::eType::Vector3, Data::MakeTypeErasedTraits<Data::eType::Vector3>());
AZ_Error("Script Canvas", it.second, "Cannot register a second Trait struct with the same ScriptCanvas type(%u)", it.first->first);
dataRegistry.m_creatableTypes.insert(it.first->second.m_dataTraits.GetSCType());
it = dataRegistry.m_typeIdTraitMap.emplace(Data::eType::Vector4, Data::MakeTypeErasedTraits<Data::eType::Vector4>());
AZ_Error("Script Canvas", it.second, "Cannot register a second Trait struct with the same ScriptCanvas type(%u)", it.first->first);
dataRegistry.m_creatableTypes.insert(it.first->second.m_dataTraits.GetSCType());
it = dataRegistry.m_typeIdTraitMap.emplace(Data::eType::AABB, Data::MakeTypeErasedTraits<Data::eType::AABB>());
AZ_Error("Script Canvas", it.second, "Cannot register a second Trait struct with the same ScriptCanvas type(%u)", it.first->first);
dataRegistry.m_creatableTypes.insert(it.first->second.m_dataTraits.GetSCType());
it = dataRegistry.m_typeIdTraitMap.emplace(Data::eType::Color, Data::MakeTypeErasedTraits<Data::eType::Color>());
AZ_Error("Script Canvas", it.second, "Cannot register a second Trait struct with the same ScriptCanvas type(%u)", it.first->first);
dataRegistry.m_creatableTypes.insert(it.first->second.m_dataTraits.GetSCType());
it = dataRegistry.m_typeIdTraitMap.emplace(Data::eType::CRC, Data::MakeTypeErasedTraits<Data::eType::CRC>());
AZ_Error("Script Canvas", it.second, "Cannot register a second Trait struct with the same ScriptCanvas type(%u)", it.first->first);
dataRegistry.m_creatableTypes.insert(it.first->second.m_dataTraits.GetSCType());
it = dataRegistry.m_typeIdTraitMap.emplace(Data::eType::Matrix3x3, Data::MakeTypeErasedTraits<Data::eType::Matrix3x3>());
AZ_Error("Script Canvas", it.second, "Cannot register a second Trait struct with the same ScriptCanvas type(%u)", it.first->first);
dataRegistry.m_creatableTypes.insert(it.first->second.m_dataTraits.GetSCType());
it = dataRegistry.m_typeIdTraitMap.emplace(Data::eType::Matrix4x4, Data::MakeTypeErasedTraits<Data::eType::Matrix4x4>());
AZ_Error("Script Canvas", it.second, "Cannot register a second Trait struct with the same ScriptCanvas type(%u)", it.first->first);
dataRegistry.m_creatableTypes.insert(it.first->second.m_dataTraits.GetSCType());
it = dataRegistry.m_typeIdTraitMap.emplace(Data::eType::Plane, Data::MakeTypeErasedTraits<Data::eType::Plane>());
AZ_Error("Script Canvas", it.second, "Cannot register a second Trait struct with the same ScriptCanvas type(%u)", it.first->first);
dataRegistry.m_creatableTypes.insert(it.first->second.m_dataTraits.GetSCType());
it = dataRegistry.m_typeIdTraitMap.emplace(Data::eType::OBB, Data::MakeTypeErasedTraits<Data::eType::OBB>());
AZ_Error("Script Canvas", it.second, "Cannot register a second Trait struct with the same ScriptCanvas type(%u)", it.first->first);
dataRegistry.m_creatableTypes.insert(it.first->second.m_dataTraits.GetSCType());
// BehaviorContext traits is slightly different than built traits
it = dataRegistry.m_typeIdTraitMap.emplace(Data::eType::BehaviorContextObject, Data::MakeTypeErasedTraits<Data::eType::BehaviorContextObject>());
AZ_Error("Script Canvas", it.second, "Cannot register a second Trait struct with the same ScriptCanvas type(%u)", it.first->first);
}
void DataRegistry::RegisterType(const AZ::TypeId& typeId, TypeProperties typeProperties)
{
Data::Type behaviorContextType = Data::FromAZType(typeId);
if (behaviorContextType.GetType() == Data::eType::BehaviorContextObject && !behaviorContextType.GetAZType().IsNull())
{
if (m_creatableTypes.find(behaviorContextType) == m_creatableTypes.end())
{
m_creatableTypes[behaviorContextType] = typeProperties;
}
}
}
void DataRegistry::UnregisterType(const AZ::TypeId& typeId)
{
Data::Type behaviorContextType = Data::FromAZType(typeId);
if (behaviorContextType.GetType() == Data::eType::BehaviorContextObject && !behaviorContextType.GetAZType().IsNull())
{
m_creatableTypes.erase(behaviorContextType);
}
}
}
@@ -0,0 +1,48 @@
/*
* 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
#include <AzCore/Module/Environment.h>
#include <ScriptCanvas/Data/Traits.h>
#include <AzCore/std/utils.h>
#include <AzCore/RTTI/ReflectContext.h>
namespace ScriptCanvas
{
struct TypeProperties
{
bool m_isTransient = false;
};
namespace Data
{
struct TypeErasedTraits;
}
struct DataRegistry final
{
AZ_TYPE_INFO(DataRegistry, "{41049FA8-EA56-401F-9720-6FE9028A1C01}");
AZ_CLASS_ALLOCATOR(DataRegistry, AZ::SystemAllocator, 0);
void RegisterType(const AZ::TypeId& typeId, TypeProperties typeProperties);
void UnregisterType(const AZ::TypeId& typeId);
AZStd::unordered_map<Data::eType, Data::TypeErasedTraits> m_typeIdTraitMap; // Creates a mapping of the Data::eType TypeId to the trait structure
AZStd::unordered_map<Data::Type, TypeProperties> m_creatableTypes;
};
void InitDataRegistry();
void ResetDataRegistry();
extern AZ::EnvironmentVariable<DataRegistry> GetDataRegistry();
static const char* s_dataRegistryName = "ScriptCanvasDataRegistry";
}
@@ -0,0 +1,31 @@
/*
* 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 <ScriptCanvas/Data/DataTrait.h>
#include <ScriptCanvas/Data/BehaviorContextObject.h>
namespace ScriptCanvas
{
namespace Data
{
eTraits<eType::BehaviorContextObject>::Type eTraits<eType::BehaviorContextObject>::GetDefault(const Data::Type& scType)
{
return BehaviorContextObject::CreateReference(scType.GetAZType());
}
bool ScriptCanvas::Data::eTraits<eType::BehaviorContextObject>::IsDefault(const Type& value, const Data::Type&)
{
return value->Get() == nullptr;
}
} // namespace Data
} // namespace ScriptCanvas
@@ -0,0 +1,511 @@
/*
* 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
#include <Data/BehaviorContextObjectPtr.h>
#include <Data/Data.h>
#include <AzFramework/Entity/EntityContextBus.h>
#include <AzFramework/Slice/SliceInstantiationTicket.h>
namespace ScriptCanvas
{
namespace Data
{
template<typename t_Type>
struct TraitsBase
{
using ThisType = TraitsBase<t_Type>;
using Type = AZStd::decay_t<t_Type>;
static const bool s_isAutoBoxed = false;
static const bool s_isKey = false;
static const bool s_isNative = false;
static const eType s_type = eType::Invalid;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<t_Type>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::FromAZType(GetAZType()); }
static AZStd::string GetName(const Data::Type& = {}) { return Data::GetName(Data::FromAZType(GetAZType())); }
// The static_assert needs to rely on the template parameter in order to avoid the clang frontend from asserting when parsing the template declaration
static Type GetDefault(const Data::Type& = {}) { static_assert((!AZStd::is_same<t_Type, t_Type>::value), "implement in the typed function"); return {}; }
static bool IsDefault(const AZStd::any&, const Data::Type& = {}) { static_assert((!AZStd::is_same<t_Type, t_Type>::value), "implement in the typed function"); return {}; }
};
template<typename t_Type>
struct Traits : public TraitsBase<t_Type>
{
};
// a compile time map of eType back to underlying AZ type and traits
template<eType>
struct eTraits
{
};
struct TypeErasedDataTraits
{
AZ_CLASS_ALLOCATOR(TypeErasedDataTraits, AZ::SystemAllocator, 0);
TypeErasedDataTraits() = default;
template<typename t_Traits>
explicit TypeErasedDataTraits(t_Traits)
{
m_isAutoBoxed = t_Traits::s_isAutoBoxed;
m_isKey = t_Traits::s_isKey;
m_isNative = t_Traits::s_isNative;
m_type = t_Traits::s_type;
m_getAZTypeCB = &t_Traits::GetAZType;
m_getSCTypeCB = &t_Traits::GetSCType;
m_getNameCB = &t_Traits::GetName;
m_getDefaultCB = [](const Data::Type& scType) -> AZStd::any
{
return AZStd::make_any<typename t_Traits::Type>(t_Traits::GetDefault(scType));
};
m_isDefaultCB = [](const AZStd::any& value, const Data::Type& scType) -> bool
{
return value.is<typename t_Traits::Type>() ? t_Traits::IsDefault(AZStd::any_cast<typename t_Traits::Type>(value), scType) : false;
};
}
AZ::Uuid GetAZType(const Data::Type& scType = {}) const { return m_getAZTypeCB ? m_getAZTypeCB(scType) : AZ::Uuid::CreateNull(); }
Data::Type GetSCType(const AZ::TypeId& typeId = AZ::TypeId::CreateNull()) const { return m_getSCTypeCB ? m_getSCTypeCB(typeId) : Data::Type::Invalid(); }
AZStd::string GetName(const Data::Type& scType = {}) const { return m_getNameCB ? m_getNameCB(scType) : ""; }
AZStd::any GetDefault(const Data::Type& scType= {}) const { return m_getDefaultCB ? m_getDefaultCB(scType) : AZStd::any{}; }
bool IsDefault(const AZStd::any& value, const Data::Type& scType = {}) const { return m_isDefaultCB ? m_isDefaultCB(value, scType) : false; }
bool m_isAutoBoxed = false;
bool m_isKey = false;
bool m_isNative = false;
eType m_type = eType::Invalid;
using GetAZTypeCB = AZ::Uuid(*)(const Data::Type&);
using GetSCTypeCB = Data::Type(*)(const AZ::TypeId&);
using GetNameCB = AZStd::string(*)(const Data::Type&);
using GetDefaultCB = AZStd::any(*)(const Data::Type&);
using IsDefaultCB = bool(*)(const AZStd::any&, const Data::Type&);
GetAZTypeCB m_getAZTypeCB{};
GetSCTypeCB m_getSCTypeCB{};
GetNameCB m_getNameCB{};
GetDefaultCB m_getDefaultCB{};
IsDefaultCB m_isDefaultCB{};
};
template<eType scTypeValue>
static TypeErasedDataTraits MakeTypeErasedDataTraits()
{
return TypeErasedDataTraits(eTraits<scTypeValue>{});
}
template<typename t_Type>
static TypeErasedDataTraits MakeTypeErasedDataTraits()
{
return TypeErasedDataTraits(Traits<t_Type>{});
}
template<>
struct Traits<AABBType> : public TraitsBase<AABBType>
{
using Type = AABBType;
static const bool s_isAutoBoxed = true;
static const bool s_isNative = true;
static const eType s_type = eType::AABB;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<AABBType>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::Type::AABB(); }
static AZStd::string GetName(const Data::Type& = {}) { return "AABB"; }
static Type GetDefault(const Data::Type& = {}) { return Data::AABBType::CreateFromMinMax(Data::Vector3Type(-.5f, -.5f, -.5f), Data::Vector3Type(.5f, .5f, .5f)); }
static bool IsDefault(const Type& value, const Data::Type& = {}) { return value == GetDefault(); }
};
template<>
struct Traits<AssetIdType> : public TraitsBase<AssetIdType>
{
using Type = AssetIdType;
static const bool s_isAutoBoxed = false;
static const bool s_isKey = true;
static const bool s_isNative = true;
static const eType s_type = eType::AssetId;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<AssetIdType>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::Type::AssetId(); }
static AZStd::string GetName(const Data::Type& = {}) { return "AssetId"; }
static Type GetDefault(const Data::Type& = {}) { return Data::AssetIdType(); }
static bool IsDefault(const Type& value, const Data::Type& = {}) { return value == GetDefault(); }
};
template<>
struct Traits<BooleanType> : public TraitsBase<BooleanType>
{
using Type = BooleanType;
static const bool s_isAutoBoxed = false;
static const bool s_isKey = true;
static const bool s_isNative = true;
static const eType s_type = eType::Boolean;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<BooleanType>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::Type::Boolean(); }
static AZStd::string GetName(const Data::Type& = {}) { return "Boolean"; }
static Type GetDefault(const Data::Type& = {}) { return false; }
static bool IsDefault(const Type& value, const Data::Type& = {}) { return value == GetDefault(); }
};
template<>
struct Traits<ColorType> : public TraitsBase<ColorType>
{
using Type = ColorType;
static const bool s_isAutoBoxed = true;
static const bool s_isNative = true;
static const eType s_type = eType::Color;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<ColorType>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::Type::Color(); }
static AZStd::string GetName(const Data::Type& = {}) { return "Color"; }
static Type GetDefault(const Data::Type& = {}) { return ColorType::CreateFromRgba(0, 0, 0, 255); }
static bool IsDefault(const Type& value, const Data::Type& = {}) { return value == GetDefault(); }
};
template<>
struct Traits<CRCType> : public TraitsBase<CRCType>
{
using Type = CRCType;
static const bool s_isAutoBoxed = true;
static const bool s_isKey = true;
static const bool s_isNative = true;
static const eType s_type = eType::CRC;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<CRCType>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::Type::CRC(); }
static AZStd::string GetName(const Data::Type& = {}) { return "CRC"; }
static Type GetDefault(const Data::Type& = {}) { return CRCType(); }
static bool IsDefault(const Type& value, const Data::Type& = {}) { return value == GetDefault(); }
};
template<>
struct Traits<EntityIDType> : public TraitsBase<EntityIDType>
{
using Type = EntityIDType;
static const bool s_isAutoBoxed = false;
static const bool s_isKey = true;
static const bool s_isNative = true;
static const eType s_type = eType::EntityID;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<EntityIDType>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::Type::EntityID(); }
static AZStd::string GetName(const Data::Type& = {}) { return "EntityID"; }
static Type GetDefault(const Data::Type& = {}) { return GraphOwnerId; }
static bool IsDefault(const Type& value, const Data::Type& = {}) { return value == GetDefault(); }
};
template<>
struct Traits<NamedEntityIDType> : public TraitsBase<NamedEntityIDType>
{
using Type = NamedEntityIDType;
static const bool s_isAutoBoxed = false;
static const bool s_isKey = true;
static const bool s_isNative = true;
static const eType s_type = eType::NamedEntityID;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<NamedEntityIDType>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::Type::NamedEntityID(); }
static AZStd::string GetName(const Data::Type& = {}) { return "NamedEntityID"; }
static Type GetDefault(const Data::Type& = {}) { return AZ::NamedEntityId(GraphOwnerId, "Self"); }
static bool IsDefault(const Type& value, const Data::Type& = {}) { return value == GetDefault(); }
};
template<>
struct Traits<Matrix3x3Type> : public TraitsBase<Matrix3x3Type>
{
using Type = Matrix3x3Type;
static const bool s_isAutoBoxed = true;
static const bool s_isNative = true;
static const eType s_type = eType::Matrix3x3;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<Matrix3x3Type>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::Type::Matrix3x3(); }
static AZStd::string GetName(const Data::Type& = {}) { return "Matrix3x3"; }
static Type GetDefault(const Data::Type& = {}) { return Matrix3x3Type::CreateIdentity(); }
static bool IsDefault(const Type& value, const Data::Type& = {}) { return value == GetDefault(); }
};
template<>
struct Traits<Matrix4x4Type> : public TraitsBase<Matrix4x4Type>
{
using Type = Matrix4x4Type;
static const bool s_isAutoBoxed = true;
static const bool s_isNative = true;
static const eType s_type = eType::Matrix4x4;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<Matrix4x4Type>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::Type::Matrix4x4(); }
static AZStd::string GetName(const Data::Type& = {}) { return "Matrix4x4"; }
static Type GetDefault(const Data::Type& = {}) { return Matrix4x4Type::CreateIdentity(); }
static bool IsDefault(const Type& value, const Data::Type& = {}) { return value == GetDefault(); }
};
template<>
struct Traits<NumberType> : public TraitsBase<NumberType>
{
using Type = NumberType;
static const bool s_isAutoBoxed = false;
static const bool s_isKey = true;
static const bool s_isNative = true;
static const eType s_type = eType::Number;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<NumberType>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::Type::Number(); }
static AZStd::string GetName(const Data::Type& = {}) { return "Number"; }
static Type GetDefault(const Data::Type& = {}) { return 0.0; }
static bool IsDefault(const Type& value, const Data::Type& = {}) { return value == GetDefault(); }
};
template<>
struct Traits<OBBType> : public TraitsBase<OBBType>
{
using Type = OBBType;
static const bool s_isAutoBoxed = true;
static const bool s_isNative = true;
static const eType s_type = eType::OBB;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<OBBType>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::Type::OBB(); }
static AZStd::string GetName(const Data::Type& = {}) { return "OBB"; }
static Type GetDefault(const Data::Type& = {}) {
return OBBType::CreateFromPositionRotationAndHalfLengths(
Vector3Type::CreateZero(),
QuaternionType::CreateIdentity(),
Vector3Type(0.5f, 0.5f, 0.5f)
);
}
static bool IsDefault(const Type& value, const Data::Type& = {}) { return value == GetDefault(); }
};
template<>
struct Traits<PlaneType> : public TraitsBase<PlaneType>
{
using Type = PlaneType;
static const bool s_isAutoBoxed = true;
static const bool s_isNative = true;
static const eType s_type = eType::Plane;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<PlaneType>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::Type::Plane(); }
static AZStd::string GetName(const Data::Type& = {}) { return "Plane"; }
static Type GetDefault(const Data::Type& = {}) { return PlaneType::CreateFromNormalAndPoint(Vector3Type(0.f, 0.f, 1.f), Vector3Type::CreateZero()); }
static bool IsDefault(const Type& value, const Data::Type& = {}) { return value == GetDefault(); }
};
template<>
struct Traits<QuaternionType> : public TraitsBase<QuaternionType>
{
using Type = QuaternionType;
static const bool s_isAutoBoxed = true;
static const bool s_isNative = true;
static const eType s_type = eType::Quaternion;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<QuaternionType>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::Type::Quaternion(); }
static AZStd::string GetName(const Data::Type& = {}) { return "Quaternion"; }
static Type GetDefault(const Data::Type& = {}) { return QuaternionType::CreateIdentity(); }
static bool IsDefault(const Type& value, const Data::Type& = {}) { return value == GetDefault(); }
};
template<>
struct Traits<StringType> : public TraitsBase<StringType>
{
using Type = StringType;
static const bool s_isAutoBoxed = false;
static const bool s_isKey = true;
static const bool s_isNative = true;
static const eType s_type = eType::String;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<StringType>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::Type::String(); }
static AZStd::string GetName(const Data::Type& = {}) { return "String"; }
static Type GetDefault(const Data::Type& = {}) { return StringType(); }
static bool IsDefault(const Type& value, const Data::Type& = {}) { return value == GetDefault(); }
};
template<>
struct Traits<TransformType> : public TraitsBase<TransformType>
{
using Type = TransformType;
static const bool s_isAutoBoxed = false;
static const bool s_isNative = true;
static const eType s_type = eType::Transform;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<TransformType>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::Type::Transform(); }
static AZStd::string GetName(const Data::Type& = {}) { return "Transform"; }
static Type GetDefault(const Data::Type& = {}) { return TransformType::CreateIdentity(); }
static bool IsDefault(const Type& value, const Data::Type& = {}) { return value == GetDefault(); }
};
template<>
struct Traits<Vector2Type> : public TraitsBase<Vector2Type>
{
using Type = Vector2Type;
static const bool s_isAutoBoxed = true;
static const bool s_isNative = true;
static const eType s_type = eType::Vector2;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<Vector2Type>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::Type::Vector2(); }
static AZStd::string GetName(const Data::Type& = {}) { return "Vector2"; }
static Type GetDefault(const Data::Type& = {}) { return Vector2Type::CreateZero(); }
static bool IsDefault(const Type& value, const Data::Type& = {}) { return value == GetDefault(); }
};
template<>
struct Traits<Vector3Type> : public TraitsBase<Vector3Type>
{
using Type = Vector3Type;
static const bool s_isAutoBoxed = true;
static const bool s_isNative = true;
static const eType s_type = eType::Vector3;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<Vector3Type>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::Type::Vector3(); }
static AZStd::string GetName(const Data::Type& = {}) { return "Vector3"; }
static Type GetDefault(const Data::Type& = {}) { return Vector3Type::CreateZero(); }
static bool IsDefault(const Type& value, const Data::Type& = {}) { return value == GetDefault(); }
};
template<>
struct Traits<Vector4Type> : public TraitsBase<Vector4Type>
{
using Type = Vector4Type;
static const bool s_isAutoBoxed = true;
static const bool s_isNative = true;
static const eType s_type = eType::Vector4;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<Vector4Type>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::Type::Vector4(); }
static AZStd::string GetName(const Data::Type& = {}) { return "Vector4"; }
static Type GetDefault(const Data::Type& = {}) { return Vector4Type::CreateZero(); }
static bool IsDefault(const Type& value, const Data::Type& = {}) { return value == GetDefault(); }
};
template<>
struct Traits<AzFramework::SliceInstantiationTicket> : public TraitsBase<AzFramework::SliceInstantiationTicket>
{
using Type = AzFramework::SliceInstantiationTicket;
static const bool s_isAutoBoxed = true;
static const bool s_isNative = false;
static const bool s_isKey = true;
static const eType s_type = eType::BehaviorContextObject;
static AZ::Uuid GetAZType(const Data::Type& = {}) { return azrtti_typeid<AzFramework::SliceInstantiationTicket>(); }
static Data::Type GetSCType(const AZ::TypeId& = AZ::TypeId::CreateNull()) { return Data::Type::BehaviorContextObject(AzFramework::SliceInstantiationTicket::TYPEINFO_Uuid()); }
static AZStd::string GetName(const Data::Type& = {}) { return "SliceInstantiationTicket"; }
static Type GetDefault(const Data::Type& = {}) { return AzFramework::SliceInstantiationTicket(); }
static bool IsDefault(const Type& value, const Data::Type& = {}) { return value == GetDefault(); }
};
/**
* Special Case Traits specialization for the string_view type
* The C++ string_view class uses the StringType traits so that in ScriptCanvas string_view maps as
* a native string type in ScriptCanvas. This to allow the common C++ concepts of a "string" to be treated
* as a string in ScriptCanvas according to the ScriptCanvas spec
*/
template<>
struct Traits<AZStd::string_view> : public Traits<StringType>
{};
/**
* Special Case Traits specialization for the const char* type
* The C++ const char* class uses the StringType traits so that in ScriptCanvas string_view maps as
* a native string type in ScriptCanvas. This to allow the common C++ concepts of a "string" to be treated
* as a string in ScriptCanvas according to the ScriptCanvas spec
*/
template<>
struct Traits<const char*> : public Traits<StringType>
{};
template<>
struct eTraits<eType::AABB> : Traits<AABBType> {};
template<>
struct eTraits<eType::AssetId> : Traits<AssetIdType> {};
template<>
struct eTraits<eType::Boolean> : Traits<BooleanType> {};
template<>
struct eTraits<eType::BehaviorContextObject>
{
using Type = BehaviorContextObjectPtr;
static const bool s_isAutoBoxed = false;
static const bool s_isNative = false;
static const bool s_isKey = false;
static const eType s_type = eType::BehaviorContextObject;
static AZ::Uuid GetAZType(const Data::Type& scType) { return scType.GetAZType(); }
static Data::Type GetSCType(const AZ::TypeId& typeId = AZ::TypeId::CreateNull()) { return Data::Type::BehaviorContextObject(typeId); }
static AZStd::string GetName(const Data::Type& scType)
{
return Data::GetBehaviorClassName(scType.GetAZType());
}
static Type GetDefault(const Data::Type& scType);
static bool IsDefault(const Type& value, const Data::Type& scType);
};
template<>
struct eTraits<eType::Color> : Traits<ColorType> {};
template<>
struct eTraits<eType::CRC> : Traits<CRCType> {};
template<>
struct eTraits<eType::EntityID> : Traits<EntityIDType> {};
template<>
struct eTraits<eType::NamedEntityID> : Traits<EntityIDType> {};
template<>
struct eTraits<eType::Matrix3x3> : Traits<Matrix3x3Type> {};
template<>
struct eTraits<eType::Matrix4x4> : Traits<Matrix4x4Type> {};
template<>
struct eTraits<eType::Number> : Traits<NumberType> {};
template<>
struct eTraits<eType::OBB> : Traits<OBBType> {};
template<>
struct eTraits<eType::Plane> : Traits<PlaneType> {};
template<>
struct eTraits<eType::Quaternion> : Traits<QuaternionType> {};
template<>
struct eTraits<eType::String> : Traits<StringType> {};
template<>
struct eTraits<eType::Transform> : Traits<TransformType> {};
template<>
struct eTraits<eType::Vector2> : Traits<Vector2Type> {};
template<>
struct eTraits<eType::Vector3> : Traits<Vector3Type> {};
template<>
struct eTraits<eType::Vector4> : Traits<Vector4Type> {};
} // namespace Data
} // namespace ScriptCanvas
@@ -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.
*
*/
#pragma once
#include <ScriptCanvas/Data/Data.h>
namespace ScriptCanvas
{
namespace Data
{
AZ_INLINE NumberType One() { return 1.0; }
AZ_INLINE NumberType ToleranceEpsilon() { return AZ::Constants::FloatEpsilon; }
AZ_INLINE NumberType ToleranceSIMD() { return 0.01; }
AZ_INLINE NumberType Zero() { return 0.0; }
}
} // namespace ScriptCanvas

Some files were not shown because too many files have changed in this diff Show More