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,549 @@
/*
* 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/Variable/GraphVariable.h>
#include <ScriptCanvas/Asset/RuntimeAsset.h>
#include <ScriptCanvas/Core/GraphScopedTypes.h>
#include <ScriptCanvas/Core/ModifiableDatumView.h>
#include <ScriptCanvas/Execution/RuntimeBus.h>
#include <ScriptCanvas/Variable/VariableBus.h>
namespace ScriptCanvas
{
void ReplicaNetworkProperties::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<ReplicaNetworkProperties>()
->Version(1)
->Field("m_isSynchronized", &ReplicaNetworkProperties::m_isSynchronized)
;
if (auto editContext = serializeContext->GetEditContext())
{
editContext->Class<ReplicaNetworkProperties>("ReplicaNetworkProperties", "Network Properties")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->DataElement(AZ::Edit::UIHandlers::CheckBox, &ReplicaNetworkProperties::m_isSynchronized, "Is Synchronized", "Controls whether or not this value is reflected across the network.")
;
}
}
}
namespace VariableFlags
{
const char* GetScopeDisplayLabel(Scope scopeType)
{
switch (scopeType)
{
case Scope::Local:
return "Local";
case Scope::Input:
return "In";
case Scope::Output:
return "Out";
case Scope::InOut:
return "In/Out";
default:
return "?";
}
}
Scope GetScopeFromLabel(const char* label)
{
if (strcmp("In", label) == 0)
{
return Scope::Input;
}
else if (strcmp("Out", label) == 0)
{
return Scope::Output;
}
else if (strcmp("In/Out", label) == 0)
{
return Scope::InOut;
}
return Scope::Local;
}
const char* GetScopeToolTip(Scope scopeType)
{
switch (scopeType)
{
case Scope::Local:
return "Variable is for use in the local scope only.";
case Scope::Input:
return "Variable will have an initial value set from an external source.";
case Scope::Output:
return "Variable will be used to return values to an external source.";
case Scope::InOut:
return "Variable will be used to receive and return values to an external source.";
default:
return "?";
}
}
}
//////////////////
// GraphVariable
//////////////////
class BehaviorVariableChangedBusHandler : public VariableNotificationBus::Handler, public AZ::BehaviorEBusHandler
{
public:
AZ_EBUS_BEHAVIOR_BINDER(BehaviorVariableChangedBusHandler, "{6469646D-EB7A-4F76-89E3-81EF05D2E688}", AZ::SystemAllocator,
OnVariableValueChanged);
// Sent when the light is turned on.
void OnVariableValueChanged() override
{
Call(FN_OnVariableValueChanged);
}
};
static bool GraphVariableVersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
{
if (classElement.GetVersion() < 3)
{
bool exposeAsInputField = false;
classElement.GetChildData<bool>(AZ_CRC("ExposeAsInput", 0x0f7879f0), exposeAsInputField);
if (exposeAsInputField)
{
classElement.RemoveElementByName(AZ_CRC("Exposure", 0x398f29cd));
classElement.AddElementWithData<VariableFlags::Scope>(context, "Scope", VariableFlags::Scope::Input);
}
else
{
AZ::u8 exposureType = VariableFlags::Deprecated::Exposure::Exp_Local;
classElement.GetChildData<AZ::u8>(AZ_CRC("Exposure", 0x398f29cd), exposureType);
VariableFlags::Scope scope = VariableFlags::Scope::Local;
if ((exposureType & VariableFlags::Deprecated::Exposure::Exp_InOut) == VariableFlags::Deprecated::Exposure::Exp_InOut)
{
scope = VariableFlags::Scope::InOut;
}
else if (exposureType & VariableFlags::Deprecated::Exposure::Exp_Input)
{
scope = VariableFlags::Scope::Input;
}
else if (exposureType & VariableFlags::Deprecated::Exposure::Exp_Output)
{
scope = VariableFlags::Scope::Output;
}
classElement.AddElementWithData<VariableFlags::Scope>(context, "Scope", scope);
}
classElement.RemoveElementByName(AZ_CRC("Exposure", 0x398f29cd));
classElement.RemoveElementByName(AZ_CRC("ExposeAsInput", 0x0f7879f0));
}
return true;
}
void GraphVariable::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
// Don't want to store the scoped id. That will need to be generated at point.
// For now we focus only on the identifier.
serializeContext->Class<GraphScopedVariableId>()
->Version(1)
->Field("Identifier", &GraphScopedVariableId::m_identifier)
;
serializeContext->Class<GraphVariable>()
->Version(3, &GraphVariableVersionConverter)
->Field("Datum", &GraphVariable::m_datum)
->Field("InputControlVisibility", &GraphVariable::m_inputControlVisibility)
->Field("ExposureCategory", &GraphVariable::m_exposureCategory)
->Field("SortPriority", &GraphVariable::m_sortPriority)
->Field("ReplicaNetProps", &GraphVariable::m_networkProperties)
->Field("VariableId", &GraphVariable::m_variableId)
->Attribute(AZ::Edit::Attributes::IdGeneratorFunction, &VariableId::MakeVariableId)
->Field("VariableName", &GraphVariable::m_variableName)
->Field("Scope", &GraphVariable::m_scope)
;
if (auto editContext = serializeContext->GetEditContext())
{
editContext->Class<GraphVariable>("Variable", "Represents a Variable field within a Script Canvas Graph")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, &GraphVariable::GetVisibility)
->Attribute(AZ::Edit::Attributes::ChildNameLabelOverride, &GraphVariable::GetDisplayName)
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &GraphVariable::GetDisplayName)
->Attribute(AZ::Edit::Attributes::DescriptionTextOverride, &GraphVariable::GetDescriptionOverride)
->DataElement(AZ::Edit::UIHandlers::ComboBox, &GraphVariable::m_scope, "Scope", "Controls the scope of this variable. i.e. If this is exposed as input to this script, or output from this script, or if the variable is just locally scoped.")
->Attribute(AZ::Edit::Attributes::Visibility, &GraphVariable::GetInputControlVisibility)
->Attribute(AZ::Edit::Attributes::GenericValueList, &GraphVariable::GetScopes)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &GraphVariable::OnScopeTypedChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &GraphVariable::m_datum, "Datum", "Datum within Script Canvas Graph")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &GraphVariable::OnValueChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &GraphVariable::m_networkProperties, "Network Properties", "Enables whether or not this value should be network synchronized")
->Attribute(AZ::Edit::Attributes::Visibility, &GraphVariable::GetScriptInputControlVisibility)
->DataElement(AZ::Edit::UIHandlers::Default, &GraphVariable::m_sortPriority, "Display Order", "Allows for customizable display order. -1 implies it will be at the end of the list.")
->Attribute(AZ::Edit::Attributes::Visibility, &GraphVariable::GetInputControlVisibility)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &GraphVariable::OnSortPriorityChanged)
->Attribute(AZ::Edit::Attributes::Min, -1)
;
}
}
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->Class<GraphScopedVariableId>()
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
;
behaviorContext->EBus<VariableNotificationBus>(GetVariableNotificationBusName(), "VariableNotificationBus", "Notifications from the Variables in the current Script Canvas graph")
->Attribute(AZ::Script::Attributes::Category, "Variables")
->Handler<BehaviorVariableChangedBusHandler>()
;
}
ReplicaNetworkProperties::Reflect(context);
}
GraphVariable::GraphVariable()
: m_sortPriority(-1)
, m_scope(VariableFlags::Scope::Local)
, m_inputControlVisibility(AZ::Edit::PropertyVisibility::Show)
, m_visibility(AZ::Edit::PropertyVisibility::ShowChildrenOnly)
, m_signalValueChanges(false)
, m_variableId(VariableId::MakeVariableId())
{
}
GraphVariable::GraphVariable(const Datum& datum)
: m_sortPriority(-1)
, m_scope(VariableFlags::Scope::Local)
, m_inputControlVisibility(AZ::Edit::PropertyVisibility::Show)
, m_visibility(AZ::Edit::PropertyVisibility::ShowChildrenOnly)
, m_signalValueChanges(false)
, m_variableId(VariableId::MakeVariableId())
, m_datum(datum)
{
}
GraphVariable::GraphVariable(Datum&& datum)
: m_sortPriority(-1)
, m_scope(VariableFlags::Scope::Local)
, m_inputControlVisibility(AZ::Edit::PropertyVisibility::Show)
, m_visibility(AZ::Edit::PropertyVisibility::ShowChildrenOnly)
, m_signalValueChanges(false)
, m_variableId(VariableId::MakeVariableId())
, m_datum(AZStd::move(datum))
{
}
GraphVariable::GraphVariable(const Datum& variableData, const VariableId& variableId)
: GraphVariable(variableData)
{
m_variableId = variableId;
}
GraphVariable::GraphVariable(Deprecated::VariableNameValuePair&& valuePair)
: GraphVariable(AZStd::move(valuePair.m_varDatum.GetData()))
{
SetVariableName(AZStd::move(valuePair.GetVariableName()));
m_variableId = valuePair.m_varDatum.GetId();
if (valuePair.m_varDatum.ExposeAsComponentInput())
{
SetScope(VariableFlags::Scope::Input);
}
else
{
SetScope(VariableFlags::Scope::Local);
}
m_inputControlVisibility = valuePair.m_varDatum.GetInputControlVisibility();
m_visibility = valuePair.m_varDatum.GetVisibility();
m_exposureCategory = valuePair.m_varDatum.GetExposureCategory();
m_signalValueChanges = valuePair.m_varDatum.AllowsSignalOnChange();
}
GraphVariable::~GraphVariable()
{
DatumNotificationBus::Handler::BusDisconnect();
}
void GraphVariable::DeepCopy(const GraphVariable& source)
{
*this = source;
m_datum.DeepCopyDatum(source.m_datum);
}
bool GraphVariable::operator==(const GraphVariable& rhs) const
{
return GetVariableId() == rhs.GetVariableId();
}
bool GraphVariable::operator!=(const GraphVariable& rhs) const
{
return !operator==(rhs);
}
const Data::Type& GraphVariable::GetDataType() const
{
return GetDatum()->GetType();
}
const VariableId& GraphVariable::GetVariableId() const
{
return m_variableId;
}
const Datum* GraphVariable::GetDatum() const
{
return &m_datum;
}
void GraphVariable::ConfigureDatumView(ModifiableDatumView& datumView)
{
datumView.ConfigureView((*this));
}
void GraphVariable::SetVariableName(AZStd::string_view variableName)
{
m_variableName = variableName;
SetDisplayName(variableName);
}
AZStd::string_view GraphVariable::GetVariableName() const
{
return m_variableName;
}
void GraphVariable::SetDisplayName(const AZStd::string& displayName)
{
m_datum.SetLabel(displayName);
}
AZStd::string_view GraphVariable::GetDisplayName() const
{
return m_datum.GetLabel();
}
void GraphVariable::SetScriptInputControlVisibility(const AZ::Crc32& inputControlVisibility)
{
m_inputControlVisibility = inputControlVisibility;
}
AZ::Crc32 GraphVariable::GetInputControlVisibility() const
{
return m_inputControlVisibility;
}
AZ::Crc32 GraphVariable::GetScriptInputControlVisibility() const
{
AZ::Data::AssetType assetType = AZ::Data::AssetType::CreateNull();
ScriptCanvas::RuntimeRequestBus::EventResult(assetType, m_scriptCanvasId, &ScriptCanvas::RuntimeRequests::GetAssetType);
if (assetType == azrtti_typeid<ScriptCanvas::RuntimeAsset>())
{
return m_inputControlVisibility;
}
else
{
return AZ::Edit::PropertyVisibility::Hide;
}
}
AZ::Crc32 GraphVariable::GetFunctionInputControlVisibility() const
{
AZ::Data::AssetType assetType = AZ::Data::AssetType::CreateNull();
ScriptCanvas::RuntimeRequestBus::EventResult(assetType, m_scriptCanvasId, &ScriptCanvas::RuntimeRequests::GetAssetType);
if (assetType == azrtti_typeid<ScriptCanvas::RuntimeFunctionAsset>())
{
return AZ::Edit::PropertyVisibility::Show;
}
else
{
return AZ::Edit::PropertyVisibility::Hide;
}
}
AZ::Crc32 GraphVariable::GetVisibility() const
{
return m_visibility;
}
void GraphVariable::SetVisibility(AZ::Crc32 visibility)
{
m_visibility = visibility;
}
void GraphVariable::RemoveScope(VariableFlags::Scope scopeType)
{
if (IsInScope(scopeType))
{
if (m_scope == VariableFlags::Scope::InOut)
{
if (scopeType == VariableFlags::Scope::Input)
{
m_scope = VariableFlags::Scope::Output;
}
else if (scopeType == VariableFlags::Scope::Output)
{
m_scope = VariableFlags::Scope::Input;
}
else
{
m_scope = VariableFlags::Scope::Local;
}
}
else
{
m_scope = VariableFlags::Scope::Local;
}
}
}
void GraphVariable::SetScope(VariableFlags::Scope scopeType)
{
if (m_scope != scopeType)
{
m_scope = scopeType;
OnScopeTypedChanged();
}
}
VariableFlags::Scope GraphVariable::GetScope() const
{
return m_scope;
}
bool GraphVariable::IsInScope(VariableFlags::Scope scopeType) const
{
switch (scopeType)
{
// All variables are local scoped
case VariableFlags::Scope::Local:
return true;
case VariableFlags::Scope::Input:
return m_scope == VariableFlags::Scope::Input || m_scope == VariableFlags::Scope::InOut;
case VariableFlags::Scope::Output:
return m_scope == VariableFlags::Scope::Output || m_scope == VariableFlags::Scope::InOut;
case VariableFlags::Scope::InOut:
return m_scope == VariableFlags::Scope::InOut;
default:
return false;
}
}
bool GraphVariable::IsLocalVariableOnly() const
{
return m_scope == VariableFlags::Scope::Local;
}
void GraphVariable::GenerateNewId()
{
m_variableId = VariableId::MakeVariableId();
}
void GraphVariable::SetAllowSignalOnChange(bool allowSignalChange)
{
m_signalValueChanges = allowSignalChange;
}
void GraphVariable::SetOwningScriptCanvasId(const ScriptCanvasId& scriptCanvasId)
{
if (m_scriptCanvasId != scriptCanvasId)
{
m_scriptCanvasId = scriptCanvasId;
if (!m_datumId.IsValid())
{
m_datumId = AZ::Entity::MakeId();
m_datum.SetNotificationsTarget(m_datumId);
DatumNotificationBus::Handler::BusConnect(m_datumId);
}
}
}
GraphScopedVariableId GraphVariable::GetGraphScopedId() const
{
return GraphScopedVariableId(m_scriptCanvasId, m_variableId);
}
void GraphVariable::OnDatumEdited([[maybe_unused]] const Datum* datum)
{
VariableNotificationBus::Event(GetGraphScopedId(), &VariableNotifications::OnVariableValueChanged);
}
AZStd::vector<AZStd::pair<AZ::u8, AZStd::string>> GraphVariable::GetScopes() const
{
AZStd::vector< AZStd::pair<AZ::u8, AZStd::string>> scopes;
scopes.emplace_back(AZStd::make_pair(VariableFlags::Scope::Local, VariableFlags::GetScopeDisplayLabel(VariableFlags::Scope::Local)));
scopes.emplace_back(AZStd::make_pair(VariableFlags::Scope::Input, VariableFlags::GetScopeDisplayLabel(VariableFlags::Scope::Input)));
if (IsInFunction())
{
scopes.emplace_back(AZStd::make_pair(VariableFlags::Scope::Output, VariableFlags::GetScopeDisplayLabel(VariableFlags::Scope::Output)));
scopes.emplace_back(AZStd::make_pair(VariableFlags::Scope::InOut, VariableFlags::GetScopeDisplayLabel(VariableFlags::Scope::InOut)));
}
return scopes;
}
int GraphVariable::GetSortPriority() const
{
return m_sortPriority;
}
bool GraphVariable::IsInFunction() const
{
AZ::Data::AssetType assetType = AZ::Data::AssetType::CreateNull();
ScriptCanvas::RuntimeRequestBus::EventResult(assetType, m_scriptCanvasId, &ScriptCanvas::RuntimeRequests::GetAssetType);
return assetType == azrtti_typeid<ScriptCanvas::RuntimeFunctionAsset>();
}
void GraphVariable::OnScopeTypedChanged()
{
VariableNotificationBus::Event(GetGraphScopedId(), &VariableNotifications::OnVariableScopeChanged);
}
void GraphVariable::OnSortPriorityChanged()
{
VariableNotificationBus::Event(GetGraphScopedId(), &VariableNotifications::OnVariablePriorityChanged);
}
void GraphVariable::OnValueChanged()
{
if (m_signalValueChanges)
{
AZ_TracePrintf("OnValueChanged", "OnValueChanged");
//VariableNotificationBus::Event(GetVariableId(), &VariableNotifications::OnVariableValueChanged);
}
}
AZStd::string GraphVariable::GetDescriptionOverride()
{
return Data::GetName(m_datum.GetType());
}
}
@@ -0,0 +1,211 @@
/*
* 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/GraphScopedTypes.h>
#include <ScriptCanvas/Variable/VariableCore.h>
#include <ScriptCanvas/Core/DatumBus.h>
// Version Conversion Information
#include <ScriptCanvas/Deprecated/VariableHelpers.h>
////
namespace ScriptCanvas
{
class ModifiableDatumView;
//! Properties that govern Datum replication
struct ReplicaNetworkProperties
{
AZ_TYPE_INFO(ReplicaNetworkProperties, "{4F055551-DD75-4877-93CE-E80C844FC155}");
AZ_CLASS_ALLOCATOR(ReplicaNetworkProperties, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* context);
bool m_isSynchronized = false;
};
namespace VariableFlags
{
namespace Deprecated
{
enum Exposure : AZ::u8
{
Exp_Local = 1 << 0,
Exp_Input = 1 << 1,
Exp_Output = 1 << 2,
Exp_InOut = (Exp_Input | Exp_Output)
};
}
enum Scope : AZ::u8
{
Local = 0,
Input = 1,
Output = 2,
InOut = 3
};
const char* GetScopeDisplayLabel(Scope scopeType);
Scope GetScopeFromLabel(const char* label);
const char* GetScopeToolTip(Scope scopeType);
}
class GraphVariable
: public DatumNotificationBus::Handler
{
friend class ModifiableDatumView;
public:
AZ_TYPE_INFO(GraphVariable, "{5BDC128B-8355-479C-8FA8-4BFFAB6915A8}");
AZ_CLASS_ALLOCATOR(GraphVariable, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* context);
static const char* GetVariableNotificationBusName() { return "VariableNotification"; }
class Comparator
{
public:
bool operator()(const GraphVariable* a, const GraphVariable* b) const
{
if (a->m_sortPriority == b->m_sortPriority)
{
return a->m_variableName < b->m_variableName;
}
if (b->m_sortPriority < 0)
{
return true;
}
if (a->m_sortPriority < 0)
{
return false;
}
return a->m_sortPriority < b->m_sortPriority;
}
};
GraphVariable();
explicit GraphVariable(const Datum& variableData);
explicit GraphVariable(Datum&& variableData);
GraphVariable(const Datum& variableData, const VariableId& variableId);
// Conversion Information
GraphVariable(Deprecated::VariableNameValuePair&& valuePair);
////
~GraphVariable();
bool operator==(const GraphVariable& rhs) const;
bool operator!=(const GraphVariable& rhs) const;
void DeepCopy(const GraphVariable& source);
const Data::Type& GetDataType() const;
const VariableId& GetVariableId() const;
const Datum* GetDatum() const;
void ConfigureDatumView(ModifiableDatumView& accessController);
void SetVariableName(AZStd::string_view displayName);
AZStd::string_view GetVariableName() const;
void SetDisplayName(const AZStd::string& displayName);
AZStd::string_view GetDisplayName() const;
void SetScriptInputControlVisibility(const AZ::Crc32& inputControlVisibility);
AZ::Crc32 GetInputControlVisibility() const;
AZ::Crc32 GetScriptInputControlVisibility() const;
AZ::Crc32 GetFunctionInputControlVisibility() const;
AZ::Crc32 GetVisibility() const;
void SetVisibility(AZ::Crc32 visibility);
void RemoveScope(VariableFlags::Scope scopeType);
void SetScope(VariableFlags::Scope scopeType);
VariableFlags::Scope GetScope() const;
bool IsInScope(VariableFlags::Scope scopeType) const;
bool IsLocalVariableOnly() const;
void SetExposureCategory(AZStd::string_view exposureCategory) { m_exposureCategory = exposureCategory; }
AZStd::string_view GetExposureCategory() const { return m_exposureCategory; }
void GenerateNewId();
void SetAllowSignalOnChange(bool allowSignalChange);
bool IsSynchronized() const { return m_networkProperties.m_isSynchronized; }
void SetOwningScriptCanvasId(const ScriptCanvasId& scriptCanvasId);
GraphScopedVariableId GetGraphScopedId() const;
// Editor Callbacks
void OnDatumEdited(const Datum* datum) override;
AZStd::vector<AZStd::pair<AZ::u8, AZStd::string>> GetScopes() const;
////
int GetSortPriority() const;
private:
bool IsInFunction() const;
void OnScopeTypedChanged();
void OnSortPriorityChanged();
void OnValueChanged();
AZStd::string GetDescriptionOverride();
int m_sortPriority;
VariableFlags::Scope m_scope;
// Still need to make this a proper bitmask, once we have support for multiple
// input/output attributes. For now, just going to assume it's only the single flag(which is is).
AZ::Crc32 m_inputControlVisibility;
AZ::Crc32 m_visibility;
AZStd::string m_exposureCategory;
bool m_signalValueChanges;
ScriptCanvasId m_scriptCanvasId;
VariableId m_variableId;
AZ::EntityId m_datumId;
AZStd::string m_variableName;
Datum m_datum;
ReplicaNetworkProperties m_networkProperties;
};
using GraphVariableMapping = AZStd::unordered_map< VariableId, GraphVariable >;
}
namespace AZ
{
}
@@ -0,0 +1,481 @@
/*
* 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/Variable/GraphVariableManagerComponent.h>
#include <ScriptCanvas/Core/Graph.h>
// Version Conversion Maintenance
#include <ScriptCanvas/Deprecated/VariableDatumBase.h>
////
namespace ScriptCanvas
{
const size_t k_maximumVariableNameSize = 200;
const char* CopiedVariableData::k_variableKey = "ScriptCanvas::CopiedVariableData";
bool GraphVariableManagerComponentVersionConverter([[maybe_unused]] AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& componentElementNode)
{
if (componentElementNode.GetVersion() < 3)
{
componentElementNode.RemoveElementByName(AZ_CRC("m_uniqueId", 0x52157a7a));
}
return true;
}
GraphVariableManagerComponent::GraphVariableManagerComponent()
{
}
GraphVariableManagerComponent::GraphVariableManagerComponent(ScriptCanvasId scriptCanvasId)
{
ConfigureScriptCanvasId(scriptCanvasId);
}
GraphVariableManagerComponent::~GraphVariableManagerComponent()
{
GraphVariableManagerRequestBus::Handler::BusDisconnect();
VariableRequestBus::MultiHandler::BusDisconnect();
}
void GraphVariableManagerComponent::Reflect(AZ::ReflectContext* context)
{
VariableId::Reflect(context);
GraphVariable::Reflect(context);
VariableData::Reflect(context);
EditableVariableConfiguration::Reflect(context);
EditableVariableData::Reflect(context);
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<CopiedVariableData>()
->Version(1)
->Field("Mapping", &CopiedVariableData::m_variableMapping)
;
serializeContext->Class<GraphVariableManagerComponent, AZ::Component>()
->Version(3, &GraphVariableManagerComponentVersionConverter)
->Field("m_variableData", &GraphVariableManagerComponent::m_variableData)
->Field("CopiedVariableRemapping", &GraphVariableManagerComponent::m_copiedVariableRemapping)
;
}
}
void GraphVariableManagerComponent::Init()
{
GraphConfigurationNotificationBus::Handler::BusConnect(GetEntityId());
}
void GraphVariableManagerComponent::Activate()
{
}
void GraphVariableManagerComponent::Deactivate()
{
}
void GraphVariableManagerComponent::ConfigureScriptCanvasId(const ScriptCanvasId& scriptCanvasId)
{
if (m_scriptCanvasId != scriptCanvasId)
{
GraphVariableManagerRequestBus::Handler::BusDisconnect();
m_scriptCanvasId = scriptCanvasId;
if (m_scriptCanvasId.IsValid())
{
GraphVariableManagerRequestBus::Handler::BusConnect(m_scriptCanvasId);
}
for (auto& varPair : m_variableData.GetVariables())
{
varPair.second.SetOwningScriptCanvasId(m_scriptCanvasId);
VariableRequestBus::MultiHandler::BusConnect(varPair.second.GetGraphScopedId());
}
}
}
GraphVariable* GraphVariableManagerComponent::GetVariable()
{
GraphVariable* graphVariable = nullptr;
if (auto variableId = VariableRequestBus::GetCurrentBusId())
{
graphVariable = m_variableData.FindVariable(variableId->m_identifier);
}
return graphVariable;
}
Data::Type GraphVariableManagerComponent::GetType() const
{
const GraphVariable* graphVariable = nullptr;
if (auto variableId = VariableRequestBus::GetCurrentBusId())
{
graphVariable = m_variableData.FindVariable(variableId->m_identifier);
}
return graphVariable ? graphVariable->GetDatum()->GetType() : Data::Type::Invalid();
}
AZStd::string_view GraphVariableManagerComponent::GetName() const
{
const GraphVariable* namedVariable = nullptr;
if (auto variableId = VariableRequestBus::GetCurrentBusId())
{
namedVariable = m_variableData.FindVariable(variableId->m_identifier);
}
return namedVariable ? AZStd::string_view(namedVariable->GetVariableName()) : "";
}
AZ::Outcome<void, AZStd::string> GraphVariableManagerComponent::RenameVariable(AZStd::string_view newVarName)
{
if (auto variableId = VariableRequestBus::GetCurrentBusId())
{
return RenameVariable(variableId->m_identifier, newVarName);
}
return AZ::Failure(AZStd::string::format("No variable id was found, cannot rename variable to %s", newVarName.data()));
}
AZ::Outcome<VariableId, AZStd::string> GraphVariableManagerComponent::CloneVariable(const GraphVariable& variableConfiguration)
{
GraphVariable copyConfiguration = variableConfiguration;
copyConfiguration.GenerateNewId();
copyConfiguration.SetOwningScriptCanvasId(m_scriptCanvasId);
AZStd::string variableName = copyConfiguration.GetVariableName();
if (FindVariable(variableName))
{
variableName.append(" (Copy)");
if (FindVariable(variableName))
{
AZStd::string originalName = variableName;
int counter = 0;
do
{
++counter;
variableName = AZStd::string::format("%s (%i)", originalName.c_str(), counter);
} while (FindVariable(variableName));
}
}
auto addOutcome = m_variableData.AddVariable(variableName, copyConfiguration);
if (!addOutcome)
{
return addOutcome;
}
const VariableId& newId = addOutcome.GetValue();
VariableRequestBus::MultiHandler::BusConnect(GraphScopedVariableId(m_scriptCanvasId, newId));
GraphVariableManagerNotificationBus::Event(GetScriptCanvasId(), &GraphVariableManagerNotifications::OnVariableAddedToGraph, newId, variableName);
return AZ::Success(newId);
}
AZ::Outcome<VariableId, AZStd::string> GraphVariableManagerComponent::RemapVariable(const GraphVariable& graphVariable)
{
if (FindVariableById(graphVariable.GetVariableId()))
{
return AZ::Success(graphVariable.GetVariableId());
}
ScriptCanvas::VariableId remappedId = FindCopiedVariableRemapping(graphVariable.GetVariableId());
if (remappedId.IsValid())
{
return AZ::Success(remappedId);
}
auto cloneOutcome = CloneVariable(graphVariable);
if (!cloneOutcome)
{
return cloneOutcome;
}
const VariableId& newId = cloneOutcome.GetValue();
// Only register a copied variable if it had a valid datum previously.
if (graphVariable.GetVariableId().IsValid())
{
RegisterCopiedVariableRemapping(graphVariable.GetVariableId(), newId);
}
return AZ::Success(newId);
}
AZ::Outcome<VariableId, AZStd::string> GraphVariableManagerComponent::AddVariable(AZStd::string_view name, const Datum& value)
{
if (FindVariable(name))
{
return AZ::Failure(AZStd::string::format("Variable %s already exists", name.data()));
}
GraphVariable newVariable(value);
newVariable.SetOwningScriptCanvasId(m_scriptCanvasId);
auto addVariableOutcome = m_variableData.AddVariable(name, newVariable);
if (!addVariableOutcome)
{
return addVariableOutcome;
}
const VariableId& newId = addVariableOutcome.GetValue();
GraphVariable* variable = m_variableData.FindVariable(newId);
variable->SetOwningScriptCanvasId(GetScriptCanvasId());
VariableRequestBus::MultiHandler::BusConnect(GraphScopedVariableId(m_scriptCanvasId, newId));
GraphVariableManagerNotificationBus::Event(GetScriptCanvasId(), &GraphVariableManagerNotifications::OnVariableAddedToGraph, newId, name);
return AZ::Success(newId);
}
AZ::Outcome<VariableId, AZStd::string> GraphVariableManagerComponent::AddVariablePair(const AZStd::pair<AZStd::string_view, Datum>& keyValuePair)
{
return AddVariable(keyValuePair.first, keyValuePair.second);
}
VariableValidationOutcome GraphVariableManagerComponent::IsNameValid(AZStd::string_view varName)
{
if (varName.size() == 0 || varName.size() >= k_maximumVariableNameSize)
{
return AZ::Failure(GraphVariableValidationErrorCode::Invalid);
}
else if (FindVariable(varName) != nullptr)
{
return AZ::Failure(GraphVariableValidationErrorCode::Duplicate);
}
else
{
return AZ::Success();
}
}
bool GraphVariableManagerComponent::RemoveVariable(const VariableId& variableId)
{
auto varNamePair = m_variableData.FindVariable(variableId);
if (varNamePair)
{
VariableRequestBus::MultiHandler::BusDisconnect(GraphScopedVariableId(m_scriptCanvasId, variableId));
VariableNotificationBus::Event(GraphScopedVariableId(m_scriptCanvasId, variableId), &VariableNotifications::OnVariableRemoved);
GraphVariableManagerNotificationBus::Event(GetScriptCanvasId(), &GraphVariableManagerNotifications::OnVariableRemovedFromGraph, variableId, varNamePair->GetVariableName());
// Bookkeeping for the copied Variable remapping
UnregisterUncopiedVariableRemapping(variableId);
return m_variableData.RemoveVariable(variableId);
}
return false;
}
AZStd::size_t GraphVariableManagerComponent::RemoveVariableByName(AZStd::string_view varName)
{
AZStd::size_t removedVars = 0U;
for (auto varIt = m_variableData.GetVariables().begin(); varIt != m_variableData.GetVariables().end();)
{
if (varIt->second.GetVariableName() == varName)
{
ScriptCanvas::VariableId variableId = varIt->first;
// Bookkeeping for the copied Variable remapping
UnregisterUncopiedVariableRemapping(variableId);
++removedVars;
VariableRequestBus::MultiHandler::BusDisconnect(GraphScopedVariableId(m_scriptCanvasId, variableId));
VariableNotificationBus::Event(GraphScopedVariableId(m_scriptCanvasId, variableId), &VariableNotifications::OnVariableRemoved);
GraphVariableManagerNotificationBus::Event(GetScriptCanvasId(), &GraphVariableManagerNotifications::OnVariableRemovedFromGraph, variableId, varName);
varIt = m_variableData.GetVariables().erase(varIt);
}
else
{
++varIt;
}
}
return removedVars;
}
GraphVariable* GraphVariableManagerComponent::FindVariable(AZStd::string_view varName)
{
return m_variableData.FindVariable(varName);
}
GraphVariable* GraphVariableManagerComponent::FindFirstVariableWithType(const Data::Type& dataType, const AZStd::unordered_set< ScriptCanvas::VariableId >& blacklistId)
{
for (auto& variablePair : m_variableData.GetVariables())
{
if (variablePair.second.GetDataType() == dataType)
{
if (blacklistId.count(variablePair.first) == 0)
{
return &variablePair.second;
}
}
}
return nullptr;
}
GraphVariable* GraphVariableManagerComponent::FindVariableById(const VariableId& variableId)
{
return m_variableData.FindVariable(variableId);
}
Data::Type GraphVariableManagerComponent::GetVariableType(const VariableId& variableId)
{
auto graphVariable = FindVariableById(variableId);
return graphVariable ? graphVariable->GetDatum()->GetType() : Data::Type::Invalid();
}
const GraphVariableMapping* GraphVariableManagerComponent::GetVariables() const
{
return &m_variableData.GetVariables();
}
GraphVariableMapping* GraphVariableManagerComponent::GetVariables()
{
return &m_variableData.GetVariables();
}
AZStd::string_view GraphVariableManagerComponent::GetVariableName(const VariableId& variableId) const
{
auto foundIt = m_variableData.GetVariables().find(variableId);
return foundIt != m_variableData.GetVariables().end() ? foundIt->second.GetVariableName() : AZStd::string_view();
}
AZ::Outcome<void, AZStd::string> GraphVariableManagerComponent::RenameVariable(const VariableId& variableId, AZStd::string_view newVarName)
{
auto varDatumPair = FindVariableById(variableId);
if (!varDatumPair)
{
return AZ::Failure(AZStd::string::format("Unable to find variable with Id %s on Entity %s. Cannot rename",
variableId.ToString().data(), GetEntityId().ToString().data()));
}
GraphVariable* graphVariable = FindVariable(newVarName);
if (graphVariable && graphVariable->GetVariableId() != variableId)
{
return AZ::Failure(AZStd::string::format("A variable with name %s already exists on Entity %s. Cannot rename",
newVarName.data(), GetEntityId().ToString().data()));
}
if (!IsNameValid(newVarName))
{
return AZ::Failure(AZStd::string::format("%s is an invalid variable name. Cannot Rename", newVarName.data()));
}
if (!m_variableData.RenameVariable(variableId, newVarName))
{
return AZ::Failure(AZStd::string::format("Unable to rename variable with id %s to %s.",
variableId.ToString().data(), newVarName.data()));
}
GraphVariableManagerNotificationBus::Event(GetScriptCanvasId(), &GraphVariableManagerNotifications::OnVariableNameChangedInGraph, variableId, newVarName);
VariableNotificationBus::Event(GraphScopedVariableId(m_scriptCanvasId, variableId), &VariableNotifications::OnVariableRenamed, newVarName);
return AZ::Success();
}
bool GraphVariableManagerComponent::IsRemappedId(const VariableId& sourceId) const
{
VariableId remappedId = FindCopiedVariableRemapping(sourceId);
return remappedId.IsValid();
}
void GraphVariableManagerComponent::SetVariableData(const VariableData& variableData)
{
VariableRequestBus::MultiHandler::BusDisconnect();
DeleteVariableData(m_variableData);
GraphVariableMapping& variableMapping = m_variableData.GetVariables();
for (const auto& varPair : variableData.GetVariables())
{
variableMapping.emplace(varPair.first, varPair.second);
}
for (auto& varPair : variableMapping)
{
varPair.second.SetOwningScriptCanvasId(GetScriptCanvasId());
VariableRequestBus::MultiHandler::BusConnect(varPair.second.GetGraphScopedId());
if (GetEntity())
{
GraphVariableManagerNotificationBus::Event(GetScriptCanvasId(), &GraphVariableManagerNotifications::OnVariableAddedToGraph, varPair.first, varPair.second.GetVariableName());
}
}
if (GetEntity())
{
GraphVariableManagerNotificationBus::Event(GetScriptCanvasId(), &GraphVariableManagerNotifications::OnVariableDataSet);
}
}
void GraphVariableManagerComponent::DeleteVariableData(const VariableData& variableData)
{
// Temporary vector to store the VariableIds in case the &variableData == &m_variableData
AZStd::vector<VariableId> variableIds;
variableIds.reserve(variableData.GetVariables().size());
for (const auto& varPair : variableData.GetVariables())
{
variableIds.push_back(varPair.first);
}
for (const auto& variableId : variableIds)
{
RemoveVariable(variableId);
}
}
VariableId GraphVariableManagerComponent::FindCopiedVariableRemapping(const VariableId& variableId) const
{
VariableId retVal;
auto mapIter = m_copiedVariableRemapping.find(variableId);
if (mapIter != m_copiedVariableRemapping.end())
{
retVal = mapIter->second;
}
return retVal;
}
void GraphVariableManagerComponent::RegisterCopiedVariableRemapping(const VariableId& originalValue, const VariableId& remappedId)
{
AZ_Error("ScriptCanvas", m_copiedVariableRemapping.find(originalValue) == m_copiedVariableRemapping.end(), "GraphVariableManagerComponent is trying to remap an original value twice");
m_copiedVariableRemapping[originalValue] = remappedId;
}
void GraphVariableManagerComponent::UnregisterUncopiedVariableRemapping(const VariableId& remappedId)
{
auto eraseIter = AZStd::find_if(m_copiedVariableRemapping.begin(), m_copiedVariableRemapping.end(), [remappedId](const AZStd::pair<VariableId, VariableId>& otherId) { return remappedId == otherId.second; });
if (eraseIter != m_copiedVariableRemapping.end())
{
m_copiedVariableRemapping.erase(eraseIter);
}
}
}
@@ -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 <AzCore/Component/Component.h>
#include <AzCore/std/containers/unordered_map.h>
#include <ScriptCanvas/Execution/ExecutionBus.h>
#include <ScriptCanvas/Variable/VariableBus.h>
#include <ScriptCanvas/Variable/VariableData.h>
#include <ScriptCanvas/Core/GraphBus.h>
namespace ScriptCanvas
{
// Implements methods to add/remove/find Script Canvas Data objects associated with the Script Canvas graph
// The VariableRequestBus is address by VariableId
// The VariableGraphIequestBus bus is addressed using the UniqueId of the ScriptCanvas Graph Component at runtime and editor time
// (NOTE: this is not the EntityId that the Graph is attached to, but an ID that is tied only to the Graph Component)
// In addition at Editor time the VariableGraphRequestBus can be address using the EntityId that this component is attached.
class GraphVariableManagerComponent
: public AZ::Component
, protected GraphConfigurationNotificationBus::Handler
, protected GraphVariableManagerRequestBus::Handler
, protected VariableRequestBus::MultiHandler
{
public:
AZ_COMPONENT(GraphVariableManagerComponent, "{825DC28D-667D-43D0-AF11-73681351DD2F}");
static void Reflect(AZ::ReflectContext* context);
GraphVariableManagerComponent();
GraphVariableManagerComponent(ScriptCanvasId scriptCanvasId);
~GraphVariableManagerComponent() override;
void Init() override;
void Activate() override;
void Deactivate() override;
// GraphConfigurationNotificationBus
void ConfigureScriptCanvasId(const ScriptCanvasId& scriptCanvasId) override;
////
ScriptCanvasId GetScriptCanvasId() const { return m_scriptCanvasId; }
//// VariableRequestBus
GraphVariable* GetVariable() override;
const GraphVariable* GetVariableConst() const override { return const_cast<GraphVariableManagerComponent*>(this)->GetVariable(); }
Data::Type GetType() const override;
AZStd::string_view GetName() const override;
AZ::Outcome<void, AZStd::string> RenameVariable(AZStd::string_view newVarName) override;
//// GraphVariableManagerRequestBus
AZ::Outcome<VariableId, AZStd::string> CloneVariable(const GraphVariable& variableConfiguration) override;
AZ::Outcome<VariableId, AZStd::string> RemapVariable(const GraphVariable& variableConfiguration) override;
AZ::Outcome<VariableId, AZStd::string> AddVariable(AZStd::string_view name, const Datum& value) override;
AZ::Outcome<VariableId, AZStd::string> AddVariablePair(const AZStd::pair<AZStd::string_view, Datum>& nameValuePair) override;
VariableValidationOutcome IsNameValid(AZStd::string_view key) override;
bool RemoveVariable(const VariableId& variableId) override;
AZStd::size_t RemoveVariableByName(AZStd::string_view variableName) override;
GraphVariable* FindVariable(AZStd::string_view propName) override;
GraphVariable* FindVariableById(const VariableId& variableId) override;
GraphVariable* FindFirstVariableWithType(const Data::Type& dataType, const AZStd::unordered_set< ScriptCanvas::VariableId >& blacklistId) override;
Data::Type GetVariableType(const VariableId& variableId) override;
const GraphVariableMapping* GetVariables() const override;
AZStd::string_view GetVariableName(const VariableId&) const override;
AZ::Outcome<void, AZStd::string> RenameVariable(const VariableId&, AZStd::string_view) override;
bool IsRemappedId(const VariableId& remappedId) const override;
////
GraphVariableMapping* GetVariables();
const VariableData* GetVariableDataConst() const override { return &m_variableData; }
VariableData* GetVariableData() override { return &m_variableData; }
void SetVariableData(const VariableData& variableData) override;
void DeleteVariableData(const VariableData& variableData) override;
protected:
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("ScriptCanvasVariableService", 0x819c8460));
}
void RegisterCopiedVariableRemapping(const VariableId& originalValue, const VariableId& remappedId);
void UnregisterUncopiedVariableRemapping(const VariableId& remappedId);
VariableId FindCopiedVariableRemapping(const VariableId& variableId) const;
VariableData m_variableData;
private:
ScriptCanvasId m_scriptCanvasId;
AZStd::unordered_map< VariableId, VariableId > m_copiedVariableRemapping;
};
}
@@ -0,0 +1,245 @@
/*
* 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/Variable/GraphVariableMarshal.h>
#include <ScriptCanvas/Variable/GraphVariable.h>
#include <ScriptCanvas/Variable/GraphVariableNetBindings.h>
#include <ScriptCanvas/Core/ModifiableDatumView.h>
#include <AzFramework/Network/EntityIdMarshaler.h>
#include <GridMate/Serialize/MathMarshal.h>
#include <GridMate/Serialize/UtilityMarshal.h>
#include <GridMate/Serialize/UuidMarshal.h>
namespace ScriptCanvas
{
void DatumMarshaler::SetNetBindingTable(GraphVariableNetBindingTable* netBindingTable)
{
m_graphVariableNetBindingTable = netBindingTable;
}
void DatumMarshaler::Marshal(GridMate::WriteBuffer& wb, const Datum* const & property) const
{
if (!property)
{
return;
}
GridMate::Marshaler<Data::eType> typeMarshaler;
const Data::eType& datumType = property->GetType().GetType();
typeMarshaler.Marshal(wb, datumType);
VariableId assetVariableId;
AZStd::unordered_map<VariableId, AZStd::pair<GraphVariable*, int>>& variableIdMap = m_graphVariableNetBindingTable->GetVariableIdMap();
for (AZStd::pair<VariableId, AZStd::pair<GraphVariable*, int>>& pair : variableIdMap)
{
AZStd::pair<GraphVariable*, int>& variableIndexPair = pair.second;
if (variableIndexPair.first->GetDatum() == property)
{
assetVariableId = m_graphVariableNetBindingTable->FindAssetVariableIdByRuntimeVariableId(pair.first);
break;
}
}
if (!assetVariableId.IsValid())
{
return;
}
GridMate::Marshaler<AZ::Uuid> uuidMarshaler;
uuidMarshaler.Marshal(wb, assetVariableId.GetDatumId());
AZStd::string uuidString = assetVariableId.m_id.ToString<AZStd::string>();
switch (datumType)
{
case Data::eType::AABB:
MarshalType<Data::AABBType>(wb, property);
break;
case Data::eType::Boolean:
MarshalType<Data::BooleanType>(wb, property);
break;
case Data::eType::Color:
MarshalType<Data::ColorType>(wb, property);
break;
case Data::eType::CRC:
MarshalType<Data::CRCType>(wb, property);
break;
case Data::eType::EntityID:
MarshalType<Data::EntityIDType>(wb, property);
break;
case Data::eType::Matrix3x3:
MarshalType<Data::Matrix3x3Type>(wb, property);
break;
case Data::eType::Matrix4x4:
MarshalType<Data::Matrix4x4Type>(wb, property);
break;
case Data::eType::NamedEntityID:
MarshalType<Data::NamedEntityIDType>(wb, property);
break;
case Data::eType::Number:
MarshalType<Data::NumberType>(wb, property);
break;
case Data::eType::OBB:
MarshalType<Data::OBBType>(wb, property);
break;
case Data::eType::Plane:
MarshalType<Data::PlaneType>(wb, property);
break;
case Data::eType::Quaternion:
MarshalType<Data::QuaternionType>(wb, property);
break;
case Data::eType::String:
MarshalType<Data::StringType>(wb, property);
break;
case Data::eType::Transform:
MarshalType<Data::TransformType>(wb, property);
break;
case Data::eType::Vector2:
MarshalType<Data::Vector2Type>(wb, property);
break;
case Data::eType::Vector3:
MarshalType<Data::Vector3Type>(wb, property);
break;
case Data::eType::Vector4:
MarshalType<Data::Vector4Type>(wb, property);
break;
default:
AZ_Warning("ScriptCanvasNetworking", false, "Marshal unsupported data type");
break;
}
}
bool DatumMarshaler::UnmarshalToPointer(const Datum*& target, GridMate::ReadBuffer& rb)
{
// :SCTODO: for some reason, this UnmarshalToPointer can get called before SetNetworkBinding is called
// (which is where we set m_graphVariableNetBindingTable). So we check for nullptr here just in case.
if (!m_graphVariableNetBindingTable)
{
return false;
}
ScriptCanvas::Data::eType datumType = Data::eType::Invalid;
GridMate::Marshaler<Data::eType> typeMarshaler;
typeMarshaler.Unmarshal(datumType, rb);
AZ::Uuid uuid;
GridMate::Marshaler<AZ::Uuid> uuidMarshaler;
uuidMarshaler.Unmarshal(uuid, rb);
VariableId runtimeVariableId = m_graphVariableNetBindingTable->FindRuntimeVariableIdByAssetVariableId(VariableId(uuid));
if (!runtimeVariableId.IsValid())
{
return false;
}
AZStd::string uuidString = runtimeVariableId.m_id.ToString<AZStd::string>();
AZStd::unordered_map<VariableId, AZStd::pair<GraphVariable*, int>>& m_variableIdMap = m_graphVariableNetBindingTable->GetVariableIdMap();
AZStd::pair<GraphVariable*, int>& variableIndexPair = m_variableIdMap[runtimeVariableId];
GraphVariable* graphVariable = variableIndexPair.first;
switch (datumType)
{
case Data::eType::AABB:
return UnmarshalType<Data::AABBType>(target, rb, graphVariable);
case Data::eType::Boolean:
return UnmarshalType<Data::BooleanType>(target, rb, graphVariable);
case Data::eType::Color:
return UnmarshalType<Data::ColorType>(target, rb, graphVariable);
case Data::eType::CRC:
return UnmarshalType<Data::CRCType>(target, rb, graphVariable);
case Data::eType::EntityID:
return UnmarshalType<Data::EntityIDType>(target, rb, graphVariable);
case Data::eType::Matrix3x3:
return UnmarshalType<Data::Matrix3x3Type>(target, rb, graphVariable);
case Data::eType::Matrix4x4:
return UnmarshalType<Data::Matrix4x4Type>(target, rb, graphVariable);
case Data::eType::NamedEntityID:
return UnmarshalType<Data::NamedEntityIDType>(target, rb, graphVariable);
case Data::eType::Number:
return UnmarshalType<Data::NumberType>(target, rb, graphVariable);
case Data::eType::OBB:
return UnmarshalType<Data::OBBType>(target, rb, graphVariable);
case Data::eType::Plane:
return UnmarshalType<Data::PlaneType>(target, rb, graphVariable);
case Data::eType::Quaternion:
return UnmarshalType<Data::QuaternionType>(target, rb, graphVariable);
case Data::eType::String:
return UnmarshalType<Data::StringType>(target, rb, graphVariable);
case Data::eType::Transform:
return UnmarshalType<Data::TransformType>(target, rb, graphVariable);
case Data::eType::Vector2:
return UnmarshalType<Data::Vector2Type>(target, rb, graphVariable);
case Data::eType::Vector3:
return UnmarshalType<Data::Vector3Type>(target, rb, graphVariable);
case Data::eType::Vector4:
return UnmarshalType<Data::Vector4Type>(target, rb, graphVariable);
default:
AZ_Warning("ScriptCanvasNetworking", false, "Unmarshal unsupported data type");
break;
}
return false;
}
void DatumThrottler::SignalDirty()
{
m_isDirty = true;
}
bool DatumThrottler::WithinThreshold(const Datum* newValue) const
{
return (newValue == nullptr || !m_isDirty);
}
void DatumThrottler::UpdateBaseline([[maybe_unused]] const Datum* baseline)
{
m_isDirty = false;
}
}
@@ -0,0 +1,86 @@
/*
* 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 <GridMate/Serialize/ContainerMarshal.h>
#include <ScriptCanvas/Core/Datum.h>
#include <ScriptCanvas/Core/ModifiableDatumView.h>
#include <ScriptCanvas/Variable/GraphVariable.h>
namespace ScriptCanvas
{
class GraphVariableNetBindingTable;
class DatumMarshaler
{
public:
void SetNetBindingTable(GraphVariableNetBindingTable* netBindingTable);
void Marshal(GridMate::WriteBuffer& wb, const Datum* const & cont) const;
bool UnmarshalToPointer(const Datum*& target, GridMate::ReadBuffer& rb);
private:
template <typename T>
void MarshalType(GridMate::WriteBuffer& wb, const Datum* const & property) const
{
GridMate::Marshaler<T> marshaler;
const T* value = property->GetAs<T>();
marshaler.Marshal(wb, *value);
}
template <typename T>
bool UnmarshalType(const Datum*& target, GridMate::ReadBuffer& rb, GraphVariable* graphVariable)
{
bool valueChanged = false;
ModifiableDatumView datumView;
if (graphVariable)
{
graphVariable->ConfigureDatumView(datumView);
if (datumView.IsValid())
{
GridMate::Marshaler<T> marshaler;
T value;
marshaler.Unmarshal(value, rb);
datumView.SetAs(value);
target = graphVariable->GetDatum();
valueChanged = true;
}
}
return valueChanged;
}
private:
//! The network binding table is needed to determine which Datum to update
//! when unmarshaling data.
// :SCTODO: synced Datums should be tracked via ID
//! and that ID should be used to lookup Datums (right now we can assume
//! which Datum should be updated, since only one Datum is supported).
GraphVariableNetBindingTable* m_graphVariableNetBindingTable = nullptr;
};
//! Simple throttler that simple operates via dirty flag.
class DatumThrottler
{
public:
DatumThrottler() = default;
void SignalDirty();
bool WithinThreshold(const Datum* newValue) const;
void UpdateBaseline(const Datum* baseline);
private:
bool m_isDirty = false;
};
}
@@ -0,0 +1,181 @@
/*
* 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/Execution/RuntimeBus.h>
#include <ScriptCanvas/Variable/GraphVariable.h>
#include <ScriptCanvas/Variable/GraphVariableNetBindings.h>
#include <ScriptCanvas/Core/Datum.h>
#include <GridMate/Replica/DataSet.h>
#include <GridMate/Replica/ReplicaFunctions.h>
#include <AzFramework/Network/NetworkContext.h>
namespace ScriptCanvas
{
const char* DatumDataSet::GetDataSetName()
{
static size_t s_chunkIndex = 0;
static const char* s_nameArray[] = {
"DataSet1","DataSet2","DataSet3","DataSet4","DataSet5",
"DataSet6","DataSet7","DataSet8","DataSet9","DataSet10",
"DataSet11","DataSet12","DataSet13","DataSet14","DataSet15",
"DataSet16","DataSet17","DataSet18","DataSet19","DataSet20",
"DataSet21","DataSet22","DataSet23","DataSet24","DataSet25",
"DataSet26","DataSet27","DataSet28","DataSet29","DataSet30",
"DataSet31","DataSet32"
};
if (s_chunkIndex > AZ_ARRAY_SIZE(s_nameArray) && AZ_ARRAY_SIZE(s_nameArray) >= 0)
{
s_chunkIndex = s_chunkIndex % AZ_ARRAY_SIZE(s_nameArray);
}
return s_nameArray[s_chunkIndex++];
}
DatumDataSet::DatumDataSet()
: DatumDataSetType(DatumDataSet::GetDataSetName())
{
}
//////////////////////////
// GraphVariableReplicaChunk
//////////////////////////
const char* GraphVariableReplicaChunk::GetChunkName()
{
return "GraphVariableReplicaChunk";
}
bool GraphVariableReplicaChunk::IsReplicaMigratable()
{
return true;
}
//////////////////////////
// GraphVariableNetBindingTable
//////////////////////////
void GraphVariableNetBindingTable::Reflect([[maybe_unused]] AZ::ReflectContext* reflect)
{
GridMate::ReplicaChunkDescriptorTable& descriptorTable = GridMate::ReplicaChunkDescriptorTable::Get();
AZ::Crc32 hash = GridMate::ReplicaChunkClassId(GraphVariableReplicaChunk::GetChunkName());
if (!descriptorTable.FindReplicaChunkDescriptor(hash))
{
descriptorTable.RegisterChunkType<GraphVariableReplicaChunk>();
}
}
GridMate::ReplicaChunkPtr GraphVariableNetBindingTable::GetNetworkBinding()
{
if (!m_replicaChunk)
{
m_replicaChunk = GridMate::CreateReplicaChunk<GraphVariableReplicaChunk>();
m_replicaChunk->SetHandler(this);
SetGraphNetBindingTable();
}
return m_replicaChunk;
}
void GraphVariableNetBindingTable::SetNetworkBinding(GridMate::ReplicaChunkPtr chunk)
{
m_replicaChunk = chunk;
m_replicaChunk->SetHandler(this);
SetGraphNetBindingTable();
}
void GraphVariableNetBindingTable::UnbindFromNetwork()
{
if (m_replicaChunk)
{
m_replicaChunk->SetHandler(nullptr);
m_replicaChunk = nullptr;
}
}
void GraphVariableNetBindingTable::OnPropertyUpdate([[maybe_unused]] const Datum* const & scriptProperty, [[maybe_unused]] const GridMate::TimeContext& tc)
{
}
void GraphVariableNetBindingTable::AddDatum(GraphVariable* variable)
{
size_t index = m_variableIdMap.size();
m_variableIdMap[variable->GetVariableId()] = AZStd::make_pair(variable, static_cast<int>(index));
}
void GraphVariableNetBindingTable::OnDatumChanged(GraphVariable& variable)
{
if (m_replicaChunk && m_replicaChunk->IsMaster())
{
GraphVariableReplicaChunk* graphVarChunk = static_cast<GraphVariableReplicaChunk*>(m_replicaChunk.get());
auto iter = m_variableIdMap.find(variable.GetVariableId());
if (iter == m_variableIdMap.end())
{
AZ_TracePrintf("ScriptCanvasNetworking", "GraphVariableNetBindingTable::OnDatumChanged: variable not found");
return;
}
const AZStd::pair<GraphVariable*, int>& pair = iter->second;
DatumDataSet& datumDataSet = graphVarChunk->m_properties[pair.second];
datumDataSet.GetThrottler().SignalDirty();
datumDataSet.Set(variable.GetDatum());
}
}
void GraphVariableNetBindingTable::SetVariableMappings(const AZStd::unordered_map<VariableId, VariableId>& assetToRuntimeVariableMap, const AZStd::unordered_map<VariableId, VariableId>& runtimeToAssetVariableMap)
{
m_assetToRuntimeVariableMap = assetToRuntimeVariableMap;
m_runtimeToAssetVariableMap = runtimeToAssetVariableMap;
}
VariableId GraphVariableNetBindingTable::FindAssetVariableIdByRuntimeVariableId(VariableId runtimeVariableId)
{
auto iter = m_runtimeToAssetVariableMap.find(runtimeVariableId);
if (iter != m_runtimeToAssetVariableMap.end())
{
return iter->second;
}
return VariableId();
}
VariableId GraphVariableNetBindingTable::FindRuntimeVariableIdByAssetVariableId(VariableId assetVariableId)
{
auto iter = m_assetToRuntimeVariableMap.find(assetVariableId);
if (iter != m_assetToRuntimeVariableMap.end())
{
return iter->second;
}
return VariableId();
}
AZStd::unordered_map<VariableId, AZStd::pair<GraphVariable*, int>>& GraphVariableNetBindingTable::GetVariableIdMap()
{
return m_variableIdMap;
}
void GraphVariableNetBindingTable::SetGraphNetBindingTable()
{
GraphVariableReplicaChunk* graphVariableChunk = static_cast<GraphVariableReplicaChunk*>(m_replicaChunk.get());
for (DatumDataSet& dataSet : graphVariableChunk->m_properties)
{
dataSet.GetMarshaler().SetNetBindingTable(this);
}
}
}
@@ -0,0 +1,101 @@
/*
* 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/ReflectContext.h>
#include <GridMate/Replica/DataSet.h>
#include <GridMate/Replica/ReplicaChunkInterface.h>
#include <GridMate/Replica/ReplicaCommon.h>
#include <ScriptCanvas/Variable/GraphVariableMarshal.h>
namespace ScriptCanvas
{
class GraphVariable;
class GraphVariableReplicaChunk;
//! Core functionality for managing replicated Datums in a script canvas and the
//! corresponding GridMate callbacks and data structs (DataSets).
class GraphVariableNetBindingTable
: public GridMate::ReplicaChunkInterface
{
public:
AZ_CLASS_ALLOCATOR(GraphVariableNetBindingTable, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* reflect);
GraphVariableNetBindingTable() = default;
~GraphVariableNetBindingTable() = default;
GridMate::ReplicaChunkPtr GetNetworkBinding();
void SetNetworkBinding(GridMate::ReplicaChunkPtr chunk);
void UnbindFromNetwork();
//! Gets called when the given Datum object is updated with a new value
//! that was received over the network.
void OnPropertyUpdate(const Datum* const & scriptProperty, const GridMate::TimeContext& tc);
//! Adds the given Datum to the list of "synced datums" for this instance.
void AddDatum(GraphVariable* variable);
//! Called when local data changes for a Datum whose values should be replicated
//! over the network.
void OnDatumChanged(GraphVariable& variable);
void SetVariableMappings(const AZStd::unordered_map<VariableId, VariableId>& assetToRuntimeVariableMap, const AZStd::unordered_map<VariableId, VariableId>& runtimeToAssetVariableMap);
VariableId FindAssetVariableIdByRuntimeVariableId(VariableId runtimeVariableId);
VariableId FindRuntimeVariableIdByAssetVariableId(VariableId assetVariableId);
AZStd::unordered_map<VariableId, AZStd::pair<GraphVariable*, int>>& GetVariableIdMap();
private:
void SetGraphNetBindingTable();
private:
AZStd::unordered_map<VariableId, VariableId> m_assetToRuntimeVariableMap;
AZStd::unordered_map<VariableId, VariableId> m_runtimeToAssetVariableMap;
//! Replica chunk used for GridMate networking binding. See GraphVariableReplicaChunk.
GridMate::ReplicaChunkPtr m_replicaChunk;
//! Contains pointers to all replicated variables contained within the runtime component
//! of the canvas this net binding is associated with.
AZStd::unordered_map<VariableId, AZStd::pair<GraphVariable*, int>> m_variableIdMap;
};
typedef GridMate::DataSet<const Datum*, DatumMarshaler, DatumThrottler>::BindInterface<GraphVariableNetBindingTable, &GraphVariableNetBindingTable::OnPropertyUpdate> DatumDataSetType;
class DatumDataSet
: public DatumDataSetType
{
public:
DatumDataSet();
~DatumDataSet() = default;
private:
const char* GetDataSetName();
};
class GraphVariableReplicaChunk
: public GridMate::ReplicaChunkBase
{
public:
AZ_CLASS_ALLOCATOR(GraphVariableReplicaChunk, AZ::SystemAllocator, 0);
static const char* GetChunkName();
GraphVariableReplicaChunk() = default;
~GraphVariableReplicaChunk() = default;
bool IsReplicaMigratable() override;
DatumDataSet m_properties[GM_MAX_DATASETS_IN_CHUNK];
};
}
@@ -0,0 +1,262 @@
/*
* 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 <AzCore/Outcome/Outcome.h>
#include <ScriptCanvas/Core/GraphScopedTypes.h>
#include <ScriptCanvas/Variable/GraphVariable.h>
namespace ScriptCanvas
{
class VariableData;
// Bus Interface for adding, removing and finding exposed Variable datums associated with a ScriptCanvas Graph
class VariableRequests
: public AZ::EBusTraits
{
public:
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = GraphScopedVariableId;
using AllocatorType = AZStd::allocator;
virtual GraphVariable* GetVariable() = 0;
virtual const GraphVariable* GetVariableConst() const = 0;
//! Returns the type associated with the specified variable.
virtual Data::Type GetType() const = 0;
//! Looks up the variable name that the variable id is associated with in the handler of the bus
virtual AZStd::string_view GetName() const = 0;
//! Changes the name of the variable with the specified @variableId within the handler
//! returns an AZ::Outcome to indicate if the variable was able to be succesfully or an error message to indicate
//! why the rename failed
virtual AZ::Outcome<void, AZStd::string> RenameVariable(AZStd::string_view newVarName) = 0;
};
using VariableRequestBus = AZ::EBus<VariableRequests>;
class CopiedVariableData
{
public:
AZ_RTTI(CopiedVariableData, "{84548415-DD9E-4943-8D1E-3E1CC49ADACB}");
AZ_CLASS_ALLOCATOR(CopiedVariableData, AZ::SystemAllocator, 0);
virtual ~CopiedVariableData() = default;
static const char* k_variableKey;
GraphVariableMapping m_variableMapping;
};
enum class GraphVariableValidationErrorCode
{
Duplicate,
Invalid,
Unknown
};
using VariableValidationOutcome = AZ::Outcome<void, GraphVariableValidationErrorCode>;
class GraphVariableManagerRequests
: public AZ::EBusTraits
{
public:
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using MutexType = AZStd::recursive_mutex;
using BusIdType = ScriptCanvasId;
using AllocatorType = AZStd::allocator;
//! Adds a variable that is keyed by the string and maps to a type that can be storedAZStd::any(any type with a AzTypeInfo specialization)
//! returns an AZ::Outcome which on success contains the VariableId and on Failure contains a string with error information
virtual AZ::Outcome<VariableId, AZStd::string> CloneVariable(const GraphVariable& baseVariable) = 0;
virtual AZ::Outcome<VariableId, AZStd::string> RemapVariable(const GraphVariable& variableConfiguration) = 0;
virtual AZ::Outcome<VariableId, AZStd::string> AddVariable(AZStd::string_view key, const Datum& value) = 0;
virtual AZ::Outcome<VariableId, AZStd::string> AddVariablePair(const AZStd::pair<AZStd::string_view, Datum>& keyValuePair) = 0;
virtual VariableValidationOutcome IsNameValid(AZStd::string_view variableName) = 0;
//! Adds properties from the range [first, last)
//! returns vector of AZ::Outcome which for successful outcomes contains the VariableId and for failing outcome
//! contains string detailing the reason for failing to add the variable
template<typename InputIt>
AZStd::vector<AZ::Outcome<VariableId, AZStd::string>> AddVariables(InputIt first, InputIt last)
{
static_assert(AZStd::is_same<typename AZStd::iterator_traits<InputIt>::value_type, AZStd::pair<AZStd::string_view, Datum>>::value, "Only iterators to pair<string_view, any> are supported");
AZStd::vector<AZ::Outcome<VariableId, AZStd::string>> addVariableOutcomes;
for (; first != last; ++first)
{
addVariableOutcomes.push_back(AddVariablePair(*first));
}
return addVariableOutcomes;
}
//! Remove a single variable which matches the specified variable id
//! returns true if the variable with the variable id was removed
virtual bool RemoveVariable(const VariableId&) = 0;
//! Removes properties which matches the specified string name
//! returns the number of properties removed
virtual AZStd::size_t RemoveVariableByName(AZStd::string_view) = 0;
//! Removes properties which matches the specified variable ids
//! returns the number of properties removed
template<typename InputIt>
AZStd::size_t RemoveVariables(InputIt first, InputIt last)
{
AZStd::size_t removedVariableCount = 0U;
static_assert(AZStd::is_same<typename AZStd::iterator_traits<InputIt>::value_type, VariableId>::value, "Only input iterators to VariableId are supported");
for (; first != last; ++first)
{
removedVariableCount += RemoveVariable(*first) ? 1 : 0;
}
return removedVariableCount;
}
//! Searches for a variable with the specified name
//! returns pointer to the first variable with the specified name or nullptr
virtual GraphVariable* FindVariable(AZStd::string_view propName) = 0;
//! Searches for a variable by VariableId
//! returns a pair of <variable datum pointer, variable name> with the supplied id
//! The variable datum pointer is non-null if the variable has been found
virtual GraphVariable* FindVariableById(const VariableId& varId) = 0;
virtual GraphVariable* FindFirstVariableWithType(const Data::Type& dataType, const AZStd::unordered_set< ScriptCanvas::VariableId >& blacklistId) = 0;
//! Returns the type associated with the specified variable.
virtual Data::Type GetVariableType(const VariableId& variableId) = 0;
//! Retrieves all properties stored by the Handler
//! returns variable container
virtual const GraphVariableMapping* GetVariables() const = 0;
//! Looks up the variable name that the variable data is associated with in the handler of the bus
virtual AZStd::string_view GetVariableName(const VariableId&) const = 0;
//! Changes the name of the variable with the specified @variableId within the handler
//! returns an AZ::Outcome to indicate if the variable was able to be succesfully or an error message to indicate
//! why the rename failed
virtual AZ::Outcome<void, AZStd::string> RenameVariable(const VariableId& variableId, AZStd::string_view newVarName) = 0;
virtual bool IsRemappedId(const VariableId& remappedId) const = 0;
virtual const VariableData* GetVariableDataConst() const = 0;
virtual VariableData* GetVariableData() = 0;
//! Sets the VariableData and connects the variables ids to the VariableRequestBus for this handler
virtual void SetVariableData(const VariableData& variableData) = 0;
//! Deletes oldVariableData and sends out GraphVariableManagerNotifications for each deleted variable
virtual void DeleteVariableData(const VariableData& variableData) = 0;
// <Deprecated>
bool IsNameAvailable(AZStd::string_view key)
{
return IsNameValid(key).IsSuccess();
}
// </Deprecated>
};
using GraphVariableManagerRequestBus = AZ::EBus<GraphVariableManagerRequests>;
class VariableNodeRequests
{
public:
// Sets the VariableId on a node that interfaces with a variable(i.e the GetVariable and SetVariable node)
virtual void SetId(const VariableId& variableId) = 0;
// Retrieves the VariableId on a node that interfaces with a variable(i.e the GetVariable and SetVariable node)
virtual const VariableId& GetId() const = 0;
};
class ScriptEventNodeRequests
{
public:
virtual void UpdateVersion() {}
};
struct RequestByNodeIdTraits : public AZ::EBusTraits
{
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = AZ::EntityId;
};
using VariableNodeRequestBus = AZ::EBus<VariableNodeRequests, RequestByNodeIdTraits>;
using ScriptEventNodeRequestBus = AZ::EBus<ScriptEventNodeRequests, RequestByNodeIdTraits>;
class GraphVariableManagerNotifications
: public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = ScriptCanvasId;
// Invoked when after a variable has been added to the handler
virtual void OnVariableAddedToGraph(const ScriptCanvas::VariableId& /*variableId*/, AZStd::string_view /*variableName*/) {}
// Invoked after a variable has been removed from the handler
virtual void OnVariableRemovedFromGraph(const ScriptCanvas::VariableId& /*variableId*/, AZStd::string_view /*variableName*/) {}
// Invoked after a variable has been renamed
virtual void OnVariableNameChangedInGraph(const ScriptCanvas::VariableId& /*variableId*/, AZStd::string_view /*variableName*/) {}
// Invoked after the variable data has been set on the variable handler
virtual void OnVariableDataSet() {}
};
using GraphVariableManagerNotificationBus = AZ::EBus<GraphVariableManagerNotifications>;
class VariableNotifications
: public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = GraphScopedVariableId;
// Invoked before a variable is erased from the Variable Bus Handler
virtual void OnVariableRemoved() {}
// Invoked after a variable is renamed
virtual void OnVariableRenamed(AZStd::string_view /*newVariableName*/) {}
virtual void OnVariableScopeChanged() {};
virtual void OnVariablePriorityChanged() {};
virtual void OnVariableValueChanged() {};
};
using VariableNotificationBus = AZ::EBus<VariableNotifications>;
class VariableNodeNotifications
: public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = AZ::EntityId;
// Invoked after the variable id has been changed on the SetVariable/GetVariableNode
virtual void OnVariableIdChanged(const VariableId& /*oldVariableId*/, const VariableId& /*newVariableId*/) {}
// Invoked after the variable has been removed from the GraphVariableManagerRequestBus
virtual void OnVariableRemovedFromNode(const VariableId& /*removedVariableId*/) {}
};
using VariableNodeNotificationBus = AZ::EBus<VariableNodeNotifications>;
}
@@ -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.
*
*/
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <ScriptCanvas/Variable/VariableCore.h>
namespace ScriptCanvas
{
VariableId VariableId::MakeVariableId()
{
return VariableId(AZ::Uuid::CreateRandom());
}
void VariableId::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<VariableId>()
->Field("m_id", &VariableId::m_id)
;
if (auto editContext = serializeContext->GetEditContext())
{
editContext->Class<VariableId>("Variable Id", "Uniquely identifies a datum. This Id can be used to address the VariableRequestBus")
->ClassElement(AZ::Edit::ClassElements::EditorData, "Variable Id")
;
}
}
}
}
@@ -0,0 +1,86 @@
/*
* 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 <ScriptCanvas/Core/Core.h>
namespace ScriptCanvas
{
enum ExposeOption : AZ::s32
{
None = 0,
ComponentInput = 1 << 0,
ComponentOutput = 1 << 1
};
struct VariableId
{
AZ_TYPE_INFO(VariableId, "{CA57A57B-E510-4C09-B952-1F43742166AE}");
AZ_CLASS_ALLOCATOR(VariableId, AZ::SystemAllocator, 0);
VariableId() = default;
VariableId(const VariableId&) = default;
explicit VariableId(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 VariableId(const char* str) = delete;
static void Reflect(AZ::ReflectContext* context);
static VariableId MakeVariableId();
const AZ::Uuid& GetDatumId() const { return m_id; }
bool IsValid() const
{
return !m_id.IsNull();
}
AZStd::string ToString() const
{
return m_id.ToString<AZStd::string>();
}
bool operator==(const VariableId& rhs) const
{
return m_id == rhs.m_id;
}
bool operator!=(const VariableId& rhs) const
{
return !operator==(rhs);
}
AZ::Uuid m_id{ AZ::Uuid::CreateNull() };
};
using NamedVariabledId = NamedId<VariableId>;
}
namespace AZStd
{
template<>
struct hash<ScriptCanvas::VariableId>
{
AZ_FORCE_INLINE size_t operator()(const ScriptCanvas::VariableId& ref) const
{
return AZStd::hash<AZ::Uuid>()(ref.GetDatumId());
}
};
}
@@ -0,0 +1,379 @@
/*
* 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/Serialization/Utils.h>
#include <ScriptCanvas/Variable/VariableData.h>
// Version Conversion
#include <ScriptCanvas/Deprecated/VariableHelpers.h>
////
namespace ScriptCanvas
{
/////////////////
// VariableData
/////////////////
static bool VariableDataVersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& rootElementNode)
{
if (rootElementNode.GetVersion() < VariableData::Version::UUID_To_Variable)
{
AZStd::unordered_map<AZ::Uuid, Deprecated::VariableNameValuePair > uuidToVariableMap;
if (!rootElementNode.GetChildData(AZ_CRC("m_nameVariableMap", 0xc4de98e7), uuidToVariableMap))
{
AZ_Error("Script Canvas", false, "Variable id in version 0 VariableData element should be AZ::Uuid");
return false;
}
rootElementNode.RemoveElementByName(AZ_CRC("m_nameVariableMap", 0xc4de98e7));
AZStd::unordered_map<VariableId, GraphVariable> idToVariableMap;
for (auto& uuidToVariableNamePair : uuidToVariableMap)
{
idToVariableMap.emplace(uuidToVariableNamePair.first, GraphVariable(AZStd::move(uuidToVariableNamePair.second)));
}
rootElementNode.AddElementWithData(context, "m_nameVariableMap", idToVariableMap);
}
else if (rootElementNode.GetVersion() < VariableData::Version::VariableDatumSimplification)
{
AZStd::unordered_map<VariableId, Deprecated::VariableNameValuePair> idToPairMap;
if (!rootElementNode.GetChildData(AZ_CRC("m_nameVariableMap", 0xc4de98e7), idToPairMap))
{
return false;
}
rootElementNode.RemoveElementByName(AZ_CRC("m_nameVariableMap", 0xc4de98e7));
AZStd::unordered_map<VariableId, GraphVariable> idToVariableMap;
for (auto& idPair : idToPairMap)
{
idToVariableMap.emplace(idPair.first, GraphVariable(AZStd::move(idPair.second)));
}
rootElementNode.AddElementWithData(context, "m_nameVariableMap", idToVariableMap);
}
return true;
}
void VariableData::Reflect(AZ::ReflectContext* context)
{
Deprecated::VariableNameValuePair::Reflect(context);
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
// Version Conversion Reflection
{
auto genericInfo = AZ::SerializeGenericTypeInfo<AZStd::unordered_map<AZ::Uuid, Deprecated::VariableNameValuePair>>::GetGenericInfo();
if (genericInfo)
{
genericInfo->Reflect(serializeContext);
}
}
{
auto genericInfo = AZ::SerializeGenericTypeInfo<AZStd::unordered_map<VariableId, Deprecated::VariableNameValuePair>>::GetGenericInfo();
if (genericInfo)
{
genericInfo->Reflect(serializeContext);
}
}
////
serializeContext->Class<VariableData>()
->Version(Version::Current, &VariableDataVersionConverter)
->Field("m_nameVariableMap", &VariableData::m_variableMap)
;
if (auto editContext = serializeContext->GetEditContext())
{
editContext->Class<VariableData>("Variables", "Variables exposed by the attached Script Canvas Graph")
->ClassElement(AZ::Edit::ClassElements::Group, "Variable Fields")
->DataElement(AZ::Edit::UIHandlers::Default, &VariableData::m_variableMap, "Variables", "Table of Variables within the Script Canvas Graph")
;
}
}
}
VariableData::VariableData(VariableData&& other)
: m_variableMap(AZStd::move(other.m_variableMap))
{
other.m_variableMap.clear();
}
VariableData& VariableData::operator=(VariableData&& other)
{
if (this != &other)
{
m_variableMap = AZStd::move(other.m_variableMap);
other.m_variableMap.clear();
}
return *this;
}
AZ::Outcome<VariableId, AZStd::string> VariableData::AddVariable(AZStd::string_view varName, const GraphVariable& graphVariable)
{
auto insertIt = m_variableMap.emplace(graphVariable.GetVariableId(), graphVariable);
if (insertIt.second)
{
insertIt.first->second.SetVariableName(varName);
return AZ::Success(insertIt.first->first);
}
return AZ::Failure(AZStd::string::format("Variable with id %s already exist in variable map. The Variable name is %s", insertIt.first->first.ToString().c_str(), insertIt.first->second.GetVariableName().data()));
}
GraphVariable* VariableData::FindVariable(AZStd::string_view variableName)
{
auto foundIt = AZStd::find_if(m_variableMap.begin(), m_variableMap.end(), [&variableName](const AZStd::pair<VariableId, GraphVariable>& variablePair)
{
return variableName == variablePair.second.GetVariableName();
});
return foundIt != m_variableMap.end() ? &foundIt->second : nullptr;
}
GraphVariable* VariableData::FindVariable(VariableId variableId)
{
AZStd::pair<AZStd::string_view, GraphVariable*> resultPair;
auto foundIt = m_variableMap.find(variableId);
return foundIt != m_variableMap.end() ? &foundIt->second : nullptr;
}
void VariableData::Clear()
{
m_variableMap.clear();
}
size_t VariableData::RemoveVariable(AZStd::string_view variableName)
{
size_t removedVars = 0U;
for (auto varIt = m_variableMap.begin(); varIt != m_variableMap.end();)
{
if (varIt->second.GetVariableName() == variableName)
{
++removedVars;
varIt = m_variableMap.erase(varIt);
}
else
{
++varIt;
}
}
return removedVars;
}
bool VariableData::RemoveVariable(const VariableId& variableId)
{
return m_variableMap.erase(variableId) != 0;
}
bool VariableData::RenameVariable(const VariableId& variableId, AZStd::string_view newVarName)
{
auto foundIt = m_variableMap.find(variableId);
if (foundIt != m_variableMap.end())
{
foundIt->second.SetVariableName(newVarName);
return true;
}
return false;
}
//////////////////////////////////
// EditableVariableDataCovnerter
//////////////////////////////////
static bool EditableVariableDataConverter(AZ::SerializeContext& serializeContext, AZ::SerializeContext::DataElementNode& rootElementNode)
{
if (rootElementNode.GetVersion() <= 1)
{
AZStd::list<Deprecated::VariableNameValuePair> varNameValueVariableList;
if (!rootElementNode.GetChildData(AZ_CRC("m_properties", 0x4227dbda), varNameValueVariableList))
{
AZ_Error("ScriptCanvas", false, "Unable to find m_properties list of VariableNameValuePairs on EditableVariableData version %d", rootElementNode.GetVersion());
return false;
}
AZStd::list<EditableVariableConfiguration> editableVariableConfigurationList;
for (auto varNameValuePair : varNameValueVariableList)
{
Datum defaultValue = varNameValuePair.m_varDatum.GetData();
editableVariableConfigurationList.push_back({ GraphVariable(AZStd::move(varNameValuePair)), defaultValue });
}
rootElementNode.RemoveElementByName(AZ_CRC("m_properties", 0x4227dbda));
rootElementNode.AddElementWithData(serializeContext, "m_variables", editableVariableConfigurationList);
}
return true;
}
void EditableVariableData::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
if (auto genericClassInfo = AZ::SerializeGenericTypeInfo<AZStd::list<Deprecated::VariableNameValuePair>>::GetGenericInfo())
{
genericClassInfo->Reflect(serializeContext);
}
serializeContext->Class<EditableVariableData>()
->Version(2, &EditableVariableDataConverter)
->Field("m_variables", &EditableVariableData::m_variables)
;
if (auto editContext = serializeContext->GetEditContext())
{
editContext->Class<EditableVariableData>("Variables", "Variables exposed by the attached Script Canvas Graph")
->ClassElement(AZ::Edit::ClassElements::Group, "Variable Fields")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Default, &EditableVariableData::m_variables, "Variables", "Array of Variables within Script Canvas Graph")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
;
}
}
}
EditableVariableData::EditableVariableData()
{
}
AZ::Outcome<void, AZStd::string> EditableVariableData::AddVariable(AZStd::string_view varName, const GraphVariable& graphVariable)
{
if (FindVariable(graphVariable.GetVariableId()))
{
return AZ::Failure(AZStd::string::format("Variable %s already exist", varName.data()));
}
m_variables.emplace_back();
EditableVariableConfiguration& newVarConfig = m_variables.back();
newVarConfig.m_graphVariable.DeepCopy(graphVariable);
newVarConfig.m_defaultValue.DeepCopyDatum((*graphVariable.GetDatum()));
newVarConfig.m_graphVariable.SetVariableName(varName);
return AZ::Success();
}
EditableVariableConfiguration* EditableVariableData::FindVariable(AZStd::string_view variableName)
{
auto foundIt = AZStd::find_if(m_variables.begin(), m_variables.end(), [&variableName](const EditableVariableConfiguration& variablePair)
{
return variableName == variablePair.m_graphVariable.GetVariableName();
});
return foundIt != m_variables.end() ? &*foundIt : nullptr;
}
EditableVariableConfiguration* EditableVariableData::FindVariable(VariableId variableId)
{
auto foundIt = AZStd::find_if(m_variables.begin(), m_variables.end(), [&variableId](const EditableVariableConfiguration& variablePair)
{
return variableId == variablePair.m_graphVariable.GetVariableId();
});
return foundIt != m_variables.end() ? &*foundIt : nullptr;
}
void EditableVariableData::Clear()
{
m_variables.clear();
}
size_t EditableVariableData::RemoveVariable(AZStd::string_view variableName)
{
size_t removedCount = 0;
auto removeIt = m_variables.begin();
while (removeIt != m_variables.end())
{
if (removeIt->m_graphVariable.GetVariableName() == variableName)
{
++removedCount;
removeIt = m_variables.erase(removeIt);
}
else
{
++removeIt;
}
}
return removedCount;
}
bool EditableVariableData::RemoveVariable(const VariableId& variableId)
{
for (auto removeIt = m_variables.begin(); removeIt != m_variables.end(); ++removeIt)
{
if (removeIt->m_graphVariable.GetVariableId() == variableId)
{
m_variables.erase(removeIt);
return true;
}
}
return false;
}
//////////////////////////////////
// EditableVariableConfiguration
//////////////////////////////////
bool EditableVariableConfiguration::VersionConverter(AZ::SerializeContext& serializeContext, AZ::SerializeContext::DataElementNode& rootElementNode)
{
if (rootElementNode.GetVersion() < Version::VariableDatumSimplification)
{
Deprecated::VariableNameValuePair varNameValuePair;
if (!rootElementNode.GetChildData(AZ_CRC("m_variableNameValuePair", 0x89adc9d0), varNameValuePair))
{
return false;
}
rootElementNode.RemoveElementByName(AZ_CRC("m_variableNameValuePair", 0x89adc9d0));
GraphVariable variable(AZStd::move(varNameValuePair));
rootElementNode.AddElementWithData(serializeContext, "GraphVariable", variable);
}
return true;
}
void EditableVariableConfiguration::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditableVariableConfiguration>()
->Version(Version::Current, &EditableVariableConfiguration::VersionConverter)
->Field("GraphVariable", &EditableVariableConfiguration::m_graphVariable)
->Field("m_defaultValue", &EditableVariableConfiguration::m_defaultValue)
;
if (auto editContext = serializeContext->GetEditContext())
{
editContext->Class<EditableVariableConfiguration>("Variable Element", "Represents a mapping of name to value")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->DataElement(AZ::Edit::UIHandlers::Default, &EditableVariableConfiguration::m_graphVariable, "Name,Value", "Variable Name and value")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
;
}
}
}
}
@@ -0,0 +1,132 @@
/*
* 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/unordered_map.h>
#include <ScriptCanvas/Variable/GraphVariable.h>
namespace ScriptCanvas
{
//! Variable Data structure for storing mappings of variable names to variable objects
class VariableData
{
public:
AZ_TYPE_INFO(VariableData, "{4F80659A-CD11-424E-BF04-AF02ABAC06B0}");
AZ_CLASS_ALLOCATOR(VariableData, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* context);
enum Version : AZ::s32
{
InitialVersion = 0,
UUID_To_Variable,
VariableDatumSimplification,
// Should always be last
Current
};
VariableData() = default;
VariableData(const VariableData&) = default;
VariableData& operator=(const VariableData&) = default;
VariableData(VariableData&&);
VariableData& operator=(VariableData&&);
AZ_INLINE GraphVariableMapping& GetVariables() { return m_variableMap; }
AZ_INLINE const GraphVariableMapping& GetVariables() const { return m_variableMap; }
AZ::Outcome<VariableId, AZStd::string> AddVariable(AZStd::string_view varName, const GraphVariable& graphVariable);
// returns GraphVariable* if found otherwise a nullptr is returned
GraphVariable* FindVariable(AZStd::string_view variableName);
GraphVariable* FindVariable(VariableId variableId);
const GraphVariable* FindVariable(AZStd::string_view variableName) const { return const_cast<VariableData*>(this)->FindVariable(variableName); }
const GraphVariable* FindVariable(VariableId variableId) const { return const_cast<VariableData*>(this)->FindVariable(variableId); }
void Clear();
// Remove all variables with supplied name
size_t RemoveVariable(AZStd::string_view variableName);
// Remove variable with supplied id
bool RemoveVariable(const VariableId& variableId);
// Rename variable with the supplied id
bool RenameVariable(const VariableId& variableId, AZStd::string_view newVarName);
private:
GraphVariableMapping m_variableMap;
};
struct EditableVariableConfiguration
{
private:
enum Version : AZ::s32
{
InitialVersion,
VariableDatumSimplification,
// Should always be last
Current
};
public:
AZ_TYPE_INFO(EditableVariableConfiguration, "{96D2F031-DEA0-44DF-82FB-2612AFB1DACF}");
AZ_CLASS_ALLOCATOR(EditableVariableConfiguration, AZ::SystemAllocator, 0);
static bool VersionConverter(AZ::SerializeContext& serializeContext, AZ::SerializeContext::DataElementNode& rootElementNode);
static void Reflect(AZ::ReflectContext* context);
GraphVariable m_graphVariable;
Datum m_defaultValue;
};
//! Variable Data structure which uses the VariableNameValuePair struct to provide editor specific UI visualization
//! for the variables within a graph. It stores uses vector instead of a map to maintain the order for that the variable values
//! were added
class EditableVariableData
{
public:
AZ_TYPE_INFO(EditableVariableData, "{D335AEC5-D118-443D-B85C-FEB17C0B26D6}");
AZ_CLASS_ALLOCATOR(EditableVariableData, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* context);
EditableVariableData();
// Returns reference to VariableNameValuePair Container
AZStd::list<EditableVariableConfiguration>& GetVariables() { return m_variables; }
const AZStd::list<EditableVariableConfiguration>& GetVariables() const { return m_variables; }
// Adds variable with the supplied name and VariableDatum
// The VariableId is retrieved from the VariableDatum
AZ::Outcome<void, AZStd::string> AddVariable(AZStd::string_view varName, const GraphVariable& varDatum);
// returns the pointer to the specified variable in m_variables. Returns nullptr if not found.
EditableVariableConfiguration* FindVariable(AZStd::string_view variableName);
EditableVariableConfiguration* FindVariable(VariableId variableId);
const EditableVariableConfiguration* FindVariable(AZStd::string_view variableName) const { return const_cast<EditableVariableData*>(this)->FindVariable(variableName); }
const EditableVariableConfiguration* FindVariable(VariableId variableId) const { return const_cast<EditableVariableData*>(this)->FindVariable(variableId); }
// Remove all variables
void Clear();
// Remove all variables with supplied name
size_t RemoveVariable(AZStd::string_view variableName);
// Remove variable with supplied id
bool RemoveVariable(const VariableId& variableId);
private:
AZStd::string m_name;
AZStd::list<EditableVariableConfiguration> m_variables;
};
} // namespace ScriptCanvas