Merge branch 'main' into LYN-3077

This commit is contained in:
amzn-sj
2021-04-22 10:11:13 -07:00
629 changed files with 29269 additions and 30244 deletions
@@ -66,7 +66,7 @@ namespace {{attribute_Namespace}}
{% set deprecationUuid = Class.attrib['DeprecationUUID'] %}
// The following will be injected directly into the source header file for which AzCodeGenerator is being run.
// The following will be injected directly into the source header file for which AZ AutoGen is being run.
// You must #include the generated header into the source header
#define SCRIPTCANVAS_NODE_{{ className }} \
public: \
@@ -158,7 +158,7 @@ return {{returnNames[0]}};
{% endfor %}
{# ExecutionOuts #}
// ExecutionOuts begin
{{ nodemacro.ExecutionOutDefinitions(Class, attribute_QualifiedName )}}
{{ nodemacro.ExecutionOutDefinitions(Class, attribute_QualifiedName)}}
// ExecutionOuts end
{# Reflect #}
void {{attribute_QualifiedName}}::Reflect(AZ::ReflectContext* context)
@@ -307,41 +307,49 @@ AZStd::tuple<{{returns|join(", ")}}>
{% for executionOut in Class.findall('Output') %}
{{ ExecutionOutDeclaration(Class, executionOut) }}
{%- endfor %}
size_t GetRequiredOutCount() const override;
{% endmacro %}
{% macro ExecutionBranchDefinition(Class, qualifiedName, executionOut) %}
{% macro ExecutionBranchDefinition(Class, qualifiedName, executionOut, outIndexBranch) %}
{% set outName = CleanName(executionOut.attrib['Name']) %}
{% set returns = executionOut.findall('Parameter') %}
{% set params = executionOut.findall('Return') %}
void {{qualifiedName}}::Call{{CleanName(outName)}}({{ExecutionOutReturnDefinition(returns)}}{{ExecutionOutParameterDefinition(returns, params)}}) {
void {{qualifiedName}}::Call{{outName}}({{ExecutionOutReturnDefinition(returns)}}{{ExecutionOutParameterDefinition(returns, params)}}) {
{% if returns|length() == 0 %}
ExecutionOut(AZ_CRC_CE("{{ executionOut.attrib['Name'] }}"){% for parameter in params %}, {{CleanName(parameter.attrib['Name'])}} {% endfor %}
ExecutionOut({{ outIndexBranch }}{% for parameter in params %}, {{CleanName(parameter.attrib['Name'])}}{% endfor %}
{% else %}
OutResult(AZ_CRC_CE("{{ executionOut.attrib['Name'] }}"), result{% for parameter in params %}, {{CleanName(parameter.attrib['Name'])}} {% endfor %}
{% endif -%});
ExecutionOutResult({{ outIndexBranch }}, result{% for parameter in params %}, {{CleanName(parameter.attrib['Name'])}}{% endfor %}
{% endif -%}); // {{ executionOut.attrib['Name'] }}
}
{% endmacro %}
{% macro ExecutionOutDefinition(Class, qualifiedName, executionOut) %}
{% macro ExecutionOutDefinition(Class, qualifiedName, executionOut, outIndexLatent) %}
{% set outName = CleanName(executionOut.attrib['Name']) %}
{% set returns = executionOut.findall('Return') %}
{% set params = executionOut.findall('Parameter') %}
void {{qualifiedName}}::Call{{CleanName(outName)}}({{ExecutionOutReturnDefinition(returns)}}{{ExecutionOutParameterDefinition(returns, params)}}) {
{% if returns|length() == 0 %}
ExecutionOut(AZ_CRC_CE("{{ executionOut.attrib['Name'] }}"){% for parameter in params %}, {{CleanName(parameter.attrib['Name'])}} {% endfor %}
ExecutionOut({{ outIndexLatent }}{% for parameter in params %}, {{CleanName(parameter.attrib['Name'])}}{% endfor %}
{% else %}
OutResult(AZ_CRC_CE("{{ executionOut.attrib['Name'] }}"), result{% for parameter in params %}, {{CleanName(parameter.attrib['Name'])}} {% endfor %}
{% endif -%} );
ExecutionOutResult({{ outIndexLatent }}, result{% for parameter in params %}, {{CleanName(parameter.attrib['Name'])}}{% endfor %}
{% endif -%}); // {{ executionOut.attrib['Name'] }}
}
{% endmacro %}
{% macro ExecutionOutDefinitions(Class, qualifiedName) %}
{% set branches = [] %}
{% for method in Class.findall('Input') %}
{%- for branch in method.findall('Branch') %}
{{ ExecutionBranchDefinition(Class, qualifiedName, branch) }}
{% if branches.append(branch) %}{% endif %}
{%- endfor %}
{% endfor %}
{%- for executionOut in Class.findall('Output') -%}
{{ ExecutionOutDefinition(Class, qualifiedName, executionOut) }}
{% endfor %}
{%- for branch in branches -%}
{{ ExecutionBranchDefinition(Class, qualifiedName, branch, loop.index0) }}
{%- endfor %}
{%- for executionOut in Class.findall('Output') -%}
{{ ExecutionOutDefinition(Class, qualifiedName, executionOut, loop.index0 + branches|length) }}
{%- endfor %}
size_t {{qualifiedName}}::GetRequiredOutCount() const { return {{Class.findall('Output')|length + branches|length}}; }
{% endmacro %}
@@ -208,7 +208,13 @@ namespace ScriptCanvas
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)
if (datum.m_storage.empty())
{
// rare, but can be caused by removals or problems with reflection to BehaviorContext, so must be checked
return nullptr;
}
else if (datum.m_type.GetType() == Data::eType::BehaviorContextObject)
{
return (*AZStd::any_cast<BehaviorContextObjectPtr>(&datum.m_storage))->CastConst<t_Value>();
}
@@ -88,17 +88,7 @@ namespace ScriptCanvas
void EBusHandler::InitializeEBusHandling(AZStd::string_view busName, AZ::BehaviorContext* behaviorContext)
{
CreateHandler(busName, behaviorContext);
const AZ::BehaviorEBusHandler::EventArray& events = m_handler->GetEvents();
AZStd::vector<AZ::Crc32> eventKeys;
eventKeys.reserve(events.size());
for (int eventIndex(0); eventIndex < events.size(); ++eventIndex)
{
eventKeys.push_back(eventIndex);
}
InitializeExecutionOuts(eventKeys);
InitializeExecutionOuts(m_handler->GetEvents().size());
}
bool EBusHandler::IsConnected() const
@@ -137,7 +127,7 @@ namespace ScriptCanvas
void EBusHandler::OnEvent(const char* /*eventName*/, const int eventIndex, AZ::BehaviorValueParameter* result, const int numParameters, AZ::BehaviorValueParameter* parameters)
{
CallOut(AZ::Crc32(eventIndex), result, parameters, numParameters);
CallOut(eventIndex, result, parameters, numParameters);
}
void EBusHandler::Reflect(AZ::ReflectContext* reflectContext)
@@ -57,7 +57,7 @@ namespace ScriptCanvas
for (size_t resultIndex = 0; resultIndex < unpackedTypes.size(); ++resultIndex)
{
const Data::Type outputType(Data::FromAZType(unpackedTypes[resultIndex]));
const Data::Type outputType = (unpackedTypes.size() == 1 && AZ::BehaviorContextHelper::IsStringParameter(*result)) ? Data::Type::String() : Data::FromAZType(unpackedTypes[resultIndex]);
const AZStd::string resultSlotName(AZStd::string::format("Result: %s", Data::GetName(outputType).data()));
SlotId addedSlotId;
@@ -3155,6 +3155,11 @@ namespace ScriptCanvas
return {};
}
AZStd::optional<size_t> Node::GetEventIndex([[maybe_unused]] AZStd::string eventName) const
{
return AZStd::nullopt;
}
AZStd::vector<SlotId> Node::GetEventSlotIds() const
{
return {};
@@ -3404,6 +3409,45 @@ namespace ScriptCanvas
return GetSlotByName("True");
}
size_t Node::GetOutIndex(const Slot& slot) const
{
size_t index = 0;
auto slotId = slot.GetId();
if (auto map = GetSlotExecutionMap())
{
auto& ins = map->GetIns();
for (auto& in : ins)
{
for (auto& out : in.outs)
{
// only count branches
if (in.outs.size() > 1)
{
if (out.slotId == slotId)
{
return index;
}
++index;
}
}
}
for (auto& latent : map->GetLatents())
{
if (latent.slotId == slotId)
{
return index;
}
++index;
}
}
return std::numeric_limits<size_t>::max();
}
AZ::Outcome<AZStd::string> Node::GetInternalOutKey(const Slot& slot) const
{
if (auto map = GetSlotExecutionMap())
@@ -700,6 +700,8 @@ namespace ScriptCanvas
// override if necessary, usually only when the node's execution topology dramatically alters at edit-time in a way that is not generally parseable
ConstSlotsOutcome GetSlotsInExecutionThreadByType(const Slot& executionSlot, CombinedSlotType targetSlotType, const Slot* executionChildSlot = nullptr) const;
size_t GetOutIndex(const Slot& slot) const;
// override if necessary, only used by NodeableNodes which can hide branched outs and rename them later
virtual AZ::Outcome<AZStd::string> GetInternalOutKey(const Slot& slot) const;
@@ -751,6 +753,8 @@ namespace ScriptCanvas
virtual AZStd::string GetEBusName() const;
virtual AZStd::optional<size_t> GetEventIndex(AZStd::string eventName) const;
virtual AZStd::vector<SlotId> GetEventSlotIds() const;
virtual AZStd::vector<SlotId> GetNonEventSlotIds() const;
@@ -19,7 +19,7 @@
namespace NodeableOutCpp
{
void NoOp(AZ::BehaviorValueParameter* /*result*/, AZ::BehaviorValueParameter* /*arguments*/, int /*numArguments*/) {}
void NoOp([[maybe_unused]] AZ::BehaviorValueParameter*, [[maybe_unused]] AZ::BehaviorValueParameter*, [[maybe_unused]] int) {}
}
namespace ScriptCanvas
@@ -36,14 +36,14 @@ namespace ScriptCanvas
{}
#if !defined(RELEASE)
void Nodeable::CallOut(const AZ::Crc32 key, AZ::BehaviorValueParameter* resultBVP, AZ::BehaviorValueParameter* argsBVPs, int numArguments) const
void Nodeable::CallOut(size_t index, AZ::BehaviorValueParameter* resultBVP, AZ::BehaviorValueParameter* argsBVPs, int numArguments) const
{
GetExecutionOutChecked(key)(resultBVP, argsBVPs, numArguments);
GetExecutionOutChecked(index)(resultBVP, argsBVPs, numArguments);
}
#else
void Nodeable::CallOut(const AZ::Crc32 key, AZ::BehaviorValueParameter* resultBVP, AZ::BehaviorValueParameter* argsBVPs, int numArguments) const
void Nodeable::CallOut(size_t index, AZ::BehaviorValueParameter* resultBVP, AZ::BehaviorValueParameter* argsBVPs, int numArguments) const
{
GetExecutionOut(key)(resultBVP, argsBVPs, numArguments);
GetExecutionOut(index)(resultBVP, argsBVPs, numArguments);
}
#endif // !defined(RELEASE)
@@ -62,11 +62,6 @@ namespace ScriptCanvas
return m_executionState->GetEntityId();
}
AZ::EntityId Nodeable::GetScriptCanvasId() const
{
return m_executionState->GetScriptCanvasId();
}
void Nodeable::Reflect(AZ::ReflectContext* reflectContext)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext))
@@ -77,9 +72,9 @@ namespace ScriptCanvas
{
editContext->Class<Nodeable>("Nodeable", "Nodeable")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, false)
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, false)
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
;
}
}
@@ -92,33 +87,45 @@ namespace ScriptCanvas
->Constructor<ExecutionStateWeakPtr>()
->Method("Deactivate", &Nodeable::Deactivate)
->Method("InitializeExecutionState", &Nodeable::InitializeExecutionState)
->Method("InitializeExecutionOuts", &Nodeable::InitializeExecutionOuts)
->Method("InitializeExecutionOutByRequiredCount", &Nodeable::InitializeExecutionOutByRequiredCount)
->Method("IsActive", &Nodeable::IsActive)
;
}
}
const FunctorOut& Nodeable::GetExecutionOut(AZ::Crc32 key) const
const FunctorOut& Nodeable::GetExecutionOut(size_t index) const
{
auto iter = m_outs.find(key);
AZ_Assert(iter != m_outs.end(), "no out registered for key: %d", key);
AZ_Assert(iter->second, "null execution methods are not allowed, key: %d", key);
return iter->second;
AZ_Assert(index < m_outs.size(), "index out of range in Nodeable::m_outs");
auto& iter = m_outs[index];
AZ_Assert(iter, "null execution methods are not allowed, index: %zu", index);
return iter;
}
const FunctorOut& Nodeable::GetExecutionOutChecked(AZ::Crc32 key) const
const FunctorOut& Nodeable::GetExecutionOutChecked(size_t index) const
{
auto iter = m_outs.find(key);
if (iter == m_outs.end())
{
return m_noOpFunctor;
}
else if (!iter->second)
if (index >= m_outs.size() && m_outs[index])
{
return m_noOpFunctor;
}
return iter->second;
return m_outs[index];
}
AZ::EntityId Nodeable::GetScriptCanvasId() const
{
return m_executionState->GetScriptCanvasId();
}
void Nodeable::InitializeExecutionOuts(size_t count)
{
m_outs.resize(count, m_noOpFunctor);
}
void Nodeable::InitializeExecutionOutByRequiredCount()
{
InitializeExecutionOuts(GetRequiredOutCount());
}
void Nodeable::InitializeExecutionState(ExecutionState* executionState)
@@ -126,37 +133,23 @@ namespace ScriptCanvas
AZ_Assert(executionState != nullptr, "execution state for nodeable must not be nullptr");
AZ_Assert(m_executionState == nullptr, "execution state already initialized");
m_executionState = executionState->WeakFromThis();
OnInitializeExecutionState();
}
void Nodeable::InitializeExecutionOuts(const AZ::Crc32* begin, const AZ::Crc32* end)
void Nodeable::SetExecutionOut(size_t index, FunctorOut&& out)
{
m_outs.reserve(end - begin);
for (; begin != end; ++begin)
{
SetExecutionOut(*begin, AZStd::move(FunctorOut(&NodeableOutCpp::NoOp)));
}
AZ_Assert(out, "null executions methods are not allowed, index: %zu", index);
m_outs[index] = AZStd::move(out);
}
void Nodeable::InitializeExecutionOuts(const AZStd::vector<AZ::Crc32>& keys)
{
InitializeExecutionOuts(keys.begin(), keys.end());
}
void Nodeable::SetExecutionOut(AZ::Crc32 key, FunctorOut&& out)
{
AZ_Assert(out, "null executions methods are not allowed, key: %d", key);
m_outs[key] = AZStd::move(out);
}
void Nodeable::SetExecutionOutChecked(AZ::Crc32 key, FunctorOut&& out)
void Nodeable::SetExecutionOutChecked(size_t index, FunctorOut&& out)
{
if (!out)
{
AZ_Error("ScriptCanvas", false, "null executions methods are not allowed, key: %d", key);
AZ_Error("ScriptCanvas", false, "null executions methods are not allowed, index: %zu", index);
return;
}
SetExecutionOut(key, AZStd::move(out));
SetExecutionOut(index, AZStd::move(out));
}
}
@@ -29,6 +29,23 @@ namespace ScriptCanvas
class SubgraphInterface;
}
/*
Note: Many parts of AzAutoGen, compilation, and runtime depend on the order of declaration and addition of slots.
The display order can be manipulated in the editor, but it will always just be a change of view.
Whenever in doubt, this is the order, in pseudo code
for in : Ins do
somethingOrdered(in)
for branch : in.Branches do
somethingOrdered(branch)
end
end
for out : Outs do
somethingOrdered(out)
end
*/
// derive from this to make an object that when wrapped with a NodeableNode can be instantly turned into a node that is easily embedded in graphs,
// and easily compiled in
class Nodeable
@@ -40,21 +57,23 @@ namespace ScriptCanvas
// reflect nodeable class API
static void Reflect(AZ::ReflectContext* reflectContext);
// the run-time constructor for non-EBus handlers
Nodeable();
// this constructor is used by EBus handlers only
Nodeable(ExecutionStateWeakPtr executionState);
virtual ~Nodeable() = default;
void CallOut(const AZ::Crc32 key, AZ::BehaviorValueParameter* resultBVP, AZ::BehaviorValueParameter* argsBVPs, int numArguments) const;
void CallOut(size_t index, AZ::BehaviorValueParameter* resultBVP, AZ::BehaviorValueParameter* argsBVPs, int numArguments) const;
AZ::Data::AssetId GetAssetId() const;
AZ::EntityId GetEntityId() const;
const Execution::FunctorOut& GetExecutionOut(AZ::Crc32 key) const;
const Execution::FunctorOut& GetExecutionOut(size_t index) const;
const Execution::FunctorOut& GetExecutionOutChecked(AZ::Crc32 key) const;
const Execution::FunctorOut& GetExecutionOutChecked(size_t index) const;
virtual NodePropertyInterface* GetPropertyInterface(AZ::Crc32 /*propertyId*/) { return nullptr; }
@@ -66,98 +85,97 @@ namespace ScriptCanvas
// any would only be good if graphs could opt into it, and execution slots could annotate changing activity level
virtual bool IsActive() const { return false; }
void InitializeExecutionOuts(const AZ::Crc32* begin, const AZ::Crc32* end);
void InitializeExecutionOuts(size_t count);
void InitializeExecutionOuts(const AZStd::vector<AZ::Crc32>& keys);
void SetExecutionOut(size_t index, Execution::FunctorOut&& out);
void SetExecutionOut(AZ::Crc32 key, Execution::FunctorOut&& out);
void SetExecutionOutChecked(AZ::Crc32 key, Execution::FunctorOut&& out);
void SetExecutionOutChecked(size_t index, Execution::FunctorOut&& out);
protected:
void InitializeExecutionOutByRequiredCount();
void InitializeExecutionState(ExecutionState* executionState);
virtual void OnInitializeExecutionState() {}
virtual void OnDeactivate() {}
// all of these hooks are known at compile time, so no branching
// we will need with and without result calls for each time for method
// methods with result but no result requested, etc
template<typename t_Return>
void OutResult(const AZ::Crc32 key, t_Return& result) const
{
// this is correct, it is up to the FunctorOut referenced by key to decide what to do with these params (whether to modify or handle strings differently)
AZ::BehaviorValueParameter resultBVP(&result);
CallOut(key, &resultBVP, nullptr, 0);
#if !defined(RELEASE)
if (!resultBVP.GetAsUnsafe<t_Return>())
{
AZ_Error("ScriptCanvas", false, "%s:CallOut(%u) failed to provide a useable result", TYPEINFO_Name(), (AZ::u32)key);
return;
}
#endif
result = *resultBVP.GetAsUnsafe<t_Return>();
}
virtual size_t GetRequiredOutCount() const { return 0; }
// Required to decay array type to pointer type
template<typename T>
using decay_array = AZStd::conditional_t<AZStd::is_array_v<AZStd::remove_reference_t<T>>, std::remove_extent_t<AZStd::remove_reference_t<T>>*, T&&>;
template<typename t_Return, typename... t_Args>
void OutResult(const AZ::Crc32 key, t_Return& result, t_Args&&... args) const
// all of these hooks are known at compile time, so no branching
// we will need with and without result calls for each type of method
// methods with result but no result requested, etc
template<typename... t_Args>
void ExecutionOut(size_t index, t_Args&&... args) const
{
// this is correct, it is up to the FunctorOut referenced by key to decide what to do with these params (whether to modify or handle strings differently)
// it is up to the FunctorOut referenced by key to decide what to do with these params (whether to modify or handle strings differently)
AZStd::tuple<decay_array<t_Args>...> lvalueWrapper(AZStd::forward<t_Args>(args)...);
using BVPReserveArray = AZStd::array<AZ::BehaviorValueParameter, sizeof...(args)>;
auto MakeBVPArrayFunction = [](auto&&... element)
{
return BVPReserveArray{ {AZ::BehaviorValueParameter{&element}...} };
};
BVPReserveArray argsBVPs = AZStd::apply(MakeBVPArrayFunction, lvalueWrapper);
AZ::BehaviorValueParameter resultBVP(&result);
CallOut(key, &resultBVP, argsBVPs.data(), sizeof...(t_Args));
BVPReserveArray argsBVPs = AZStd::apply(MakeBVPArrayFunction, lvalueWrapper);
CallOut(index, nullptr, argsBVPs.data(), sizeof...(t_Args));
}
void ExecutionOut(size_t index) const
{
// it is up to the FunctorOut referenced by key to decide what to do with these params (whether to modify or handle strings differently)
CallOut(index, nullptr, nullptr, 0);
}
template<typename t_Return>
void ExecutionOutResult(size_t index, t_Return& result) const
{
// It is up to the FunctorOut referenced by the index to decide what to do with these params (whether to modify or handle strings differently)
AZ::BehaviorValueParameter resultBVP(&result);
CallOut(index, &resultBVP, nullptr, 0);
#if !defined(RELEASE)
if (!resultBVP.GetAsUnsafe<t_Return>())
{
AZ_Error("ScriptCanvas", false, "%s:CallOut(%u) failed to provide a useable result", TYPEINFO_Name(), (AZ::u32)key);
AZ_Error("ScriptCanvas", false, "%s:CallOut(%zu) failed to provide a useable result", TYPEINFO_Name(), index);
return;
}
#endif
result = *resultBVP.GetAsUnsafe<t_Return>();
}
template<typename... t_Args>
void ExecutionOut(const AZ::Crc32 key, t_Args&&... args) const
template<typename t_Return, typename... t_Args>
void ExecutionOutResult(size_t index, t_Return& result, t_Args&&... args) const
{
// this is correct, it is up to the FunctorOut referenced by key to decide what to do with these params (whether to modify or handle strings differently)
// it is up to the FunctorOut referenced by key to decide what to do with these params (whether to modify or handle strings differently)
AZStd::tuple<decay_array<t_Args>...> lvalueWrapper(AZStd::forward<t_Args>(args)...);
using BVPReserveArray = AZStd::array<AZ::BehaviorValueParameter, sizeof...(args)>;
auto MakeBVPArrayFunction = [](auto&&... element)
{
return BVPReserveArray{ {AZ::BehaviorValueParameter{&element}...} };
};
BVPReserveArray argsBVPs = AZStd::apply(MakeBVPArrayFunction, lvalueWrapper);
AZ::BehaviorValueParameter resultBVP(&result);
CallOut(index, &resultBVP, argsBVPs.data(), sizeof...(t_Args));
CallOut(key, nullptr, argsBVPs.data(), sizeof...(t_Args));
#if !defined(RELEASE)
if (!resultBVP.GetAsUnsafe<t_Return>())
{
AZ_Error("ScriptCanvas", false, "%s:CallOut(%zu) failed to provide a useable result", TYPEINFO_Name(), index);
return;
}
#endif
result = *resultBVP.GetAsUnsafe<t_Return>();
}
void ExecutionOut(const AZ::Crc32 key) const
{
// this is correct, it is up to the FunctorOut referenced by key to decide what to do with these params (whether to modify or handle strings differently)
CallOut(key, nullptr, nullptr, 0);
}
private:
// keep this here, and don't even think about putting it back in the FunctorOuts by any method*, lambda capture or other.
// programmers will need this for internal node state debugging and who knows what other reasons
// * Lua execution is an exception
ExecutionStateWeakPtr m_executionState = nullptr;
Execution::FunctorOut m_noOpFunctor;
AZStd::unordered_map<AZ::Crc32, Execution::FunctorOut> m_outs;
AZStd::vector<Execution::FunctorOut> m_outs;
};
}
@@ -91,19 +91,6 @@ namespace ScriptCanvas
AZ_Error("ScriptCanvas", m_nodeable, "null Nodeable in NodeableNode::ConfigureSlots");
}
AZ::Outcome<AZStd::pair<size_t, size_t>> NodeableNode::FindMethodAndInputIndexOfSlot(const SlotId& slotID) const
{
if (auto thisSlot = GetSlot(slotID))
{
if (thisSlot->GetType() == CombinedSlotType::DataIn)
{
return m_slotExecutionMap.FindInAndInputIndexOfSlot(slotID);
}
}
return AZ::Failure();
}
AZ::Outcome<const AZ::BehaviorClass*, AZStd::string> NodeableNode::GetBehaviorContextClass() const
{
AZ::BehaviorContext* behaviorContext = NodeableNodeCpp::GetBehaviorContext();
@@ -73,8 +73,6 @@ namespace ScriptCanvas
void ConfigureSlots() override;
AZ::Outcome<AZStd::pair<size_t, size_t>> FindMethodAndInputIndexOfSlot(const SlotId& slotID) const;
AZ::Outcome<const AZ::BehaviorClass*, AZStd::string> GetBehaviorContextClass() const;
ConstSlotsOutcome GetBehaviorContextOutName(const Slot& inSlot) const;
@@ -105,11 +105,9 @@ namespace ScriptCanvas
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())
auto dataRegistry = GetDataRegistry();
if (dataRegistry->IsUseableInSlot(scType))
{
m_datum.SetType(scType);
}
@@ -152,22 +152,6 @@ namespace ScriptCanvas
return nullptr;
}
AZ::Outcome<AZStd::pair<size_t, size_t>> Map::FindInAndInputIndexOfSlot(const SlotId& slotID) const
{
for (const auto& in : m_ins)
{
auto inputIter = find_if(in.inputs, [&slotID](const Input& input) { return input.slotId == slotID; });
if (inputIter != in.inputs.end())
{
const size_t inIndex = &in - m_ins.begin();
const size_t inputIndex = inputIter - in.inputs.begin();
return AZ::Success(AZStd::make_pair(inIndex, inputIndex));
}
}
return AZ::Failure();
}
const In* Map::FindInFromInputSlot(const SlotId& slotID) const
{
auto iter = find_if
@@ -124,8 +124,6 @@ namespace ScriptCanvas
Map(Outs&& latents);
AZ::Outcome<AZStd::pair<size_t, size_t>> FindInAndInputIndexOfSlot(const SlotId& slotID) const;
const In* FindInFromInputSlot(const SlotId& slotID) const;
SlotId FindInputSlotIdBySource(VariableId inputSourceId, Grammar::FunctionSourceId inSourceId) const;
@@ -209,13 +209,18 @@ namespace ScriptCanvas
m_latents.push_back(out);
}
void SubgraphInterface::AddOutKey(const AZStd::string& name)
bool SubgraphInterface::AddOutKey(const AZStd::string& name)
{
const AZ::Crc32 key(name);
if (AZStd::find(m_outKeys.begin(), m_outKeys.end(), key) == m_outKeys.end())
{
m_outKeys.push_back(key);
return true;
}
else
{
return false;
}
}
@@ -708,7 +713,7 @@ namespace ScriptCanvas
}
// Populates the list of out keys
void SubgraphInterface::Parse()
AZ::Outcome<void, AZStd::string> SubgraphInterface::Parse()
{
m_outKeys.clear();
@@ -716,14 +721,22 @@ namespace ScriptCanvas
{
for (const auto& out : in.outs)
{
AddOutKey(out.displayName);
if (!AddOutKey(out.displayName))
{
return AZ::Failure(AZStd::string::format("Out %s was already in the list", out.displayName.c_str()));
}
}
}
for (const auto& latent : m_latents)
{
AddOutKey(latent.displayName);
if (!AddOutKey(latent.displayName))
{
return AZ::Failure(AZStd::string::format("Out %s was already in the list", latent.displayName.c_str()));
}
}
return AZ::Success();
}
void SubgraphInterface::Reflect(AZ::ReflectContext* refectContext)
@@ -232,7 +232,7 @@ namespace ScriptCanvas
bool operator==(const SubgraphInterface& rhs) const;
// Populates the list of out keys
void Parse();
AZ::Outcome<void, AZStd::string> Parse();
bool RequiresConstructionParameters() const;
@@ -266,7 +266,7 @@ namespace ScriptCanvas
AZStd::vector<AZ::Crc32> m_outKeys;
NamespacePath m_namespacePath;
void AddOutKey(const AZStd::string& name);
bool AddOutKey(const AZStd::string& name);
const Out* FindImmediateOut(const AZStd::string& in, const AZStd::string& out) const;
const In* FindIn(const AZStd::string& inSlotId) const;
const Out* FindLatentOut(const AZStd::string& latent) const;
@@ -389,29 +389,6 @@ namespace ScriptCanvas
return AZ::Utils::IsVectorContainerType(ToAZType(type));
}
bool IsAllowedBehaviorClassVariableType(const AZ::Uuid& id)
{
AZ::BehaviorContext* behaviorContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationRequests::GetBehaviorContext);
AZ_Assert(behaviorContext, "Unable to retrieve behavior context.");
const auto& classIterator = behaviorContext->m_typeToClassMap.find(id);
if (classIterator != behaviorContext->m_typeToClassMap.end())
{
AZ::BehaviorClass* behaviorClass = classIterator->second;
if (behaviorClass->FindAttribute(AZ::ScriptCanvasAttributes::VariableCreationForbidden))
{
return false;
}
}
else
{
return false;
}
return true;
}
bool IsSetContainerType(const AZ::Uuid& type)
{
return AZ::Utils::IsSetContainerType(type);
@@ -197,8 +197,6 @@ namespace ScriptCanvas
bool IsVectorContainerType(const AZ::Uuid& type);
bool IsVectorContainerType(const Type& type);
bool IsAllowedBehaviorClassVariableType(const AZ::Uuid& id);
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);
@@ -105,14 +105,24 @@ namespace ScriptCanvas
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)
void DataRegistry::RegisterType(const AZ::TypeId& typeId, TypeProperties typeProperties, Createability registration)
{
Data::Type behaviorContextType = Data::FromAZType(typeId);
if (behaviorContextType.GetType() == Data::eType::BehaviorContextObject && !behaviorContextType.GetAZType().IsNull())
{
if (m_creatableTypes.find(behaviorContextType) == m_creatableTypes.end())
if (registration == Createability::SlotAndVariable)
{
m_creatableTypes[behaviorContextType] = typeProperties;
if (m_creatableTypes.find(behaviorContextType) == m_creatableTypes.end())
{
m_creatableTypes[behaviorContextType] = typeProperties;
}
}
else if (registration == Createability::SlotOnly)
{
if (m_slottableTypes.find(behaviorContextType) == m_slottableTypes.end())
{
m_slottableTypes[behaviorContextType] = typeProperties;
}
}
}
}
@@ -125,4 +135,15 @@ namespace ScriptCanvas
m_creatableTypes.erase(behaviorContextType);
}
}
}
bool DataRegistry::IsUseableInSlot(const Data::Type& scType) const
{
return m_creatableTypes.contains(scType) || m_slottableTypes.contains(scType);
}
bool DataRegistry::IsUseableInSlot(const AZ::TypeId& typeId) const
{
Data::Type scType = Data::FromAZType(typeId);
return IsUseableInSlot(scType);
}
}
@@ -34,11 +34,21 @@ namespace ScriptCanvas
AZ_TYPE_INFO(DataRegistry, "{41049FA8-EA56-401F-9720-6FE9028A1C01}");
AZ_CLASS_ALLOCATOR(DataRegistry, AZ::SystemAllocator, 0);
void RegisterType(const AZ::TypeId& typeId, TypeProperties typeProperties);
enum class Createability
{
None,
SlotAndVariable,
SlotOnly,
};
void RegisterType(const AZ::TypeId& typeId, TypeProperties typeProperties, Createability registration);
void UnregisterType(const AZ::TypeId& typeId);
bool IsUseableInSlot(const AZ::TypeId& typeId) const;
bool IsUseableInSlot(const Data::Type& type) const;
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;
AZStd::unordered_map<Data::Type, TypeProperties> m_slottableTypes;
};
void InitDataRegistry();
@@ -508,11 +508,10 @@ namespace ScriptCanvas
const int argsCount = lua_gettop(lua);
AZ_Assert(argsCount >= 2, "CallExecutionOut: Error in compiled Lua file, not enough arguments");
AZ_Assert(lua_isuserdata(lua, 1), "CallExecutionOut: Error in compiled lua file, 1st argument to SetExecutionOut is not userdata (Nodeable)");
AZ_Assert(lua_isstring(lua, 2), "CallExecutionOut: Error in compiled lua file, 2nd argument to SetExecutionOut is not a string (Crc key)");
AZ_Assert(lua_isnumber(lua, 2), "CallExecutionOut: Error in compiled lua file, 2nd argument to SetExecutionOut is not a number");
Nodeable* nodeable = AZ::ScriptValue<Nodeable*>::StackRead(lua, 1);
const char* keyStr = AZ::ScriptValue<const char*>::StackRead(lua, 2);
AZ_Assert(keyStr, "CallExecutionOut: Failed to read key string");
nodeable->CallOut(AZ::Crc32(keyStr), nullptr, nullptr, argsCount - 2);
size_t index = aznumeric_caster(lua_tointeger(lua, -2));
nodeable->CallOut(index, nullptr, nullptr, argsCount - 2);
// Lua: results...
return lua_gettop(lua);
}
@@ -559,23 +558,14 @@ namespace ScriptCanvas
int InitializeNodeableOutKeys(lua_State* lua)
{
using namespace ExecutionInterpretedAPICpp;
// Lua: usernodeable, outKeys...
// Lua: usernodeable, keyCount
const int argsCount = lua_gettop(lua);
AZ_Assert(argsCount >= 2, "InitializeNodeableOutKeys: Error in compiled Lua file, not enough arguments");
AZ_Assert((argsCount - 1) < k_MaxNodeableOuts, "InitializeNodeableOutKeys: Error in compiled Lua file, too many outs for nodeable out)");
AZ_Assert(argsCount == 2, "InitializeNodeableOutKeys: Error in compiled Lua file, not enough arguments");
AZ_Assert(lua_isuserdata(lua, 1), "InitializeNodeableOutKeys: Error in compiled lua file, 1st argument to SetExecutionOut is not userdata (Nodeable)");
Nodeable* nodeable = AZ::ScriptValue<Nodeable*>::StackRead(lua, 1);
const int keyCount = argsCount - 1;
AZStd::array<AZ::Crc32, k_MaxNodeableOuts> keys;
for (int argumentIndex = 2, sentinel = argsCount + 1; argumentIndex != sentinel; ++argumentIndex)
{
AZ_Assert(lua_isnumber(lua, argumentIndex), "InitializeNodeableOutKeys: Error in compiled lua file, argument at Lua index #%d was not an integer", argumentIndex);
keys[argumentIndex - 2] = static_cast<AZ::u32>(lua_tointeger(lua, argumentIndex));
}
nodeable->InitializeExecutionOuts(keys.begin(), keys.begin() + keyCount);
AZ_Assert(lua_isnumber(lua, 2), "InitializeNodeableOutKeys: Error in compiled lua file, 2nd argument was not an integer");
const size_t keyCount = aznumeric_caster(lua_tointeger(lua, 2));
nodeable->InitializeExecutionOuts(keyCount);
return 0;
}
@@ -595,19 +585,18 @@ namespace ScriptCanvas
// \see https://jira.agscollab.com/browse/LY-99750
AZ_Assert(lua_isuserdata(lua, -3), "Error in compiled lua file, 1st argument to SetExecutionOut is not userdata (Nodeable)");
AZ_Assert(lua_isstring(lua, -2), "Error in compiled lua file, 2nd argument to SetExecutionOut is not a string (Crc key)");
AZ_Assert(lua_isnumber(lua, -2), "Error in compiled lua file, 2nd argument to SetExecutionOut is not a number");
AZ_Assert(lua_isfunction(lua, -1), "Error in compiled lua file, 3rd argument to SetExecutionOut is not a function (lambda need to get around atypically routed arguments)");
Nodeable* nodeable = AZ::ScriptValue<Nodeable*>::StackRead(lua, -3);
AZ_Assert(nodeable, "Failed to read nodeable");
const char* keyStr = AZ::ScriptValue<const char*>::StackRead(lua, -2);
AZ_Assert(keyStr, "Failed to read key string");
// Lua: nodeable, string, lambda
size_t index = aznumeric_caster(lua_tointeger(lua, -2));
// Lua: nodeable, index, lambda
lua_pushvalue(lua, -1);
// Lua: nodeable, string, lambda, lambda
// Lua: nodeable, index, lambda, lambda
nodeable->SetExecutionOut(AZ::Crc32(keyStr), OutInterpreted(lua));
// Lua: nodeable, string, lambda
nodeable->SetExecutionOut(index, OutInterpreted(lua));
// Lua: nodeable, index, lambda
// \todo clear these immediately after they are not needed with an explicit call written by the translator
return 0;
@@ -618,20 +607,19 @@ namespace ScriptCanvas
// \note Return values could become necessary.
// \see https://jira.agscollab.com/browse/LY-99750
AZ_Assert(lua_isuserdata(lua, -3), "Error in compiled lua file, 1st argument to SetExecutionOut is not userdata (Nodeable)");
AZ_Assert(lua_isstring(lua, -2), "Error in compiled lua file, 2nd argument to SetExecutionOut is not a string (Crc key)");
AZ_Assert(lua_isfunction(lua, -1), "Error in compiled lua file, 3rd argument to SetExecutionOut is not a function (lambda need to get around atypically routed arguments)");
AZ_Assert(lua_isuserdata(lua, -3), "Error in compiled lua file, 1st argument to SetExecutionOutResult is not userdata (Nodeable)");
AZ_Assert(lua_isnumber(lua, -2), "Error in compiled lua file, 2nd argument to SetExecutionOutResult is not a number");
AZ_Assert(lua_isfunction(lua, -1), "Error in compiled lua file, 3rd argument to SetExecutionOutResult is not a function (lambda need to get around atypically routed arguments)");
Nodeable* nodeable = AZ::ScriptValue<Nodeable*>::StackRead(lua, -3); // this won't be a BCO, because BCOs won't be necessary in the interpreted mode...most likely
AZ_Assert(nodeable, "Failed to read nodeable");
const char* keyStr = AZ::ScriptValue<const char*>::StackRead(lua, -2);
AZ_Assert(keyStr, "Failed to read key string");
// Lua: nodeable, string, lambda
size_t index = aznumeric_caster(lua_tointeger(lua, -2));
// Lua: nodeable, index, lambda
lua_pushvalue(lua, -1);
// Lua: nodeable, string, lambda, lambda
// Lua: nodeable, index, lambda, lambda
nodeable->SetExecutionOut(AZ::Crc32(keyStr), OutInterpretedResult(lua));
// Lua: nodeable, string, lambda
nodeable->SetExecutionOut(index, OutInterpretedResult(lua));
// Lua: nodeable, index, lambda
// \todo clear these immediately after they are not needed with an explicit call written by the translator
return 0;
@@ -639,20 +627,19 @@ namespace ScriptCanvas
int SetExecutionOutUserSubgraph(lua_State* lua)
{
AZ_Assert(lua_isuserdata(lua, -3), "Error in compiled lua file, 1st argument to SetExecutionOut is not userdata (Nodeable)");
AZ_Assert(lua_isstring(lua, -2), "Error in compiled lua file, 2nd argument to SetExecutionOut is not a string (Crc key)");
AZ_Assert(lua_isfunction(lua, -1), "Error in compiled lua file, 3rd argument to SetExecutionOut is not a function (lambda need to get around atypically routed arguments)");
AZ_Assert(lua_isuserdata(lua, -3), "Error in compiled lua file, 1st argument to SetExecutionOutUserSubgraph is not userdata (Nodeable)");
AZ_Assert(lua_isnumber(lua, -2), "Error in compiled lua file, 2nd argument to SetExecutionOutUserSubgraph is not a number");
AZ_Assert(lua_isfunction(lua, -1), "Error in compiled lua file, 3rd argument to SetExecutionOutUserSubgraph is not a function (lambda need to get around atypically routed arguments)");
Nodeable* nodeable = AZ::ScriptValue<Nodeable*>::StackRead(lua, -3);
AZ_Assert(nodeable, "Failed to read nodeable");
const char* keyStr = AZ::ScriptValue<const char*>::StackRead(lua, -2);
AZ_Assert(keyStr, "Failed to read key string");
// Lua: nodeable, string, lambda
size_t index = aznumeric_caster(lua_tointeger(lua, -2));
// Lua: nodeable, index, lambda
lua_pushvalue(lua, -1);
// Lua: nodeable, string, lambda, lambda
// Lua: nodeable, index, lambda, lambda
nodeable->SetExecutionOut(AZ::Crc32(keyStr), OutInterpretedUserSubgraph(lua));
// Lua: nodeable, string, lambda
nodeable->SetExecutionOut(index, OutInterpretedUserSubgraph(lua));
// Lua: nodeable, index, lambda
// \todo clear these immediately after they are not needed with an explicit call written by the translator
return 0;
@@ -83,7 +83,7 @@ namespace ScriptCanvas
int EBusHandlerCreateAndConnectTo(lua_State* lua)
{
// Lua: executionState, (event name) string, (address aztypeid) string, (address) ?
// Lua: executionState, (ebus name) string, (address aztypeid) string, (address) ?
auto executionState = AZ::ScriptValue<ExecutionStateInterpreted*>::StackRead(lua, 1);
auto ebusName = AZ::ScriptValue<const char*>::StackRead(lua, 2);
EBusHandler* ebusHandler = aznew EBusHandler(executionState->WeakFromThis(), ebusName, AZ::ScriptContext::FromNativeContext(lua)->GetBoundContext());
@@ -96,7 +96,7 @@ namespace ScriptCanvas
ebusHandler->ConnectTo(address);
AZ::Internal::LuaClassToStack(lua, ebusHandler, azrtti_typeid<EBusHandler>(), AZ::ObjectToLua::ByReference, AZ::AcquisitionOnPush::ScriptAcquire);
// Lua: executionState, (event name) string, (address aztypeid) string, (address) ?, handler
// Lua: executionState, (ebus name) string, (address aztypeid) string, (address) ?, handler
return 1;
}
@@ -114,27 +114,23 @@ namespace ScriptCanvas
const int k_eventNameIndex = -2;
const int k_lambdaIndex = -1;
AZ_Assert(lua_isuserdata(lua, k_nodeableIndex), "Error in compiled lua file, 1st argument to SetExecutionOut is not userdata (Nodeable)");
AZ_Assert(lua_isstring(lua, k_eventNameIndex), "Error in compiled lua file, 2nd argument to SetExecutionOut is not a string (Crc key)");
AZ_Assert(lua_isfunction(lua, k_lambdaIndex), "Error in compiled lua file, 3rd argument to SetExecutionOut is not a function (lambda need to get around atypically routed arguments)");
AZ_Assert(lua_isuserdata(lua, k_nodeableIndex), "Error in compiled lua file, 1st argument to EBusHandlerHandleEvent is not userdata (EBusHandler)");
AZ_Assert(lua_isnumber(lua, k_eventNameIndex), "Error in compiled lua file, 2nd argument to EBusHandlerHandleEvent is not a number");
AZ_Assert(lua_isfunction(lua, k_lambdaIndex), "Error in compiled lua file, 3rd argument to EBusHandlerHandleEvent is not a function");
auto nodeable = AZ::ScriptValue<EBusHandler*>::StackRead(lua, k_nodeableIndex); // this won't be a BCO, because BCOs won't be necessary in the interpreted mode...most likely
auto nodeable = AZ::ScriptValue<EBusHandler*>::StackRead(lua, k_nodeableIndex);
AZ_Assert(nodeable, "Failed to read EBusHandler");
const char* keyStr = lua_tostring(lua, k_eventNameIndex);
AZ_Assert(keyStr, "Failed to read key string");
const int eventIndex = nodeable->GetEventIndex(keyStr);
AZ_Assert(eventIndex != -1, "Event index was not found for %s-%s", nodeable->GetEBusName().data(), keyStr);
const int eventIndex = lua_tointeger(lua, k_eventNameIndex);
AZ_Assert(eventIndex != -1, "Event index was not found for %s", nodeable->GetEBusName().data());
// install the generic hook for the event
nodeable->HandleEvent(eventIndex);
// Lua: nodeable, string, lambda
lua_pushvalue(lua, k_lambdaIndex);
// Lua: nodeable, string, lambda, lambda
// route the event handling to the lambda on the top of the stack
nodeable->SetExecutionOut(AZ::Crc32(eventIndex), OutInterpreted(lua));
// Lua: nodeable, string, lambda
return 0;
}
@@ -145,16 +141,14 @@ namespace ScriptCanvas
const int k_eventNameIndex = -2;
const int k_lambdaIndex = -1;
AZ_Assert(lua_isuserdata(lua, k_nodeableIndex), "Error in compiled lua file, 1st argument to SetExecutionOut is not userdata (Nodeable)");
AZ_Assert(lua_isstring(lua, k_eventNameIndex), "Error in compiled lua file, 2nd argument to SetExecutionOut is not a string (Crc key)");
AZ_Assert(lua_isfunction(lua, k_lambdaIndex), "Error in compiled lua file, 3rd argument to SetExecutionOut is not a function (lambda need to get around atypically routed arguments)");
AZ_Assert(lua_isuserdata(lua, k_nodeableIndex), "Error in compiled lua file, 1st argument to EBusHandlerHandleEventResult is not userdata (EBusHandler)");
AZ_Assert(lua_isnumber(lua, k_eventNameIndex), "Error in compiled lua file, 2nd argument to EBusHandlerHandleEventResult is not a number");
AZ_Assert(lua_isfunction(lua, k_lambdaIndex), "Error in compiled lua file, 3rd argument to EBusHandlerHandleEventResult is not a function");
auto nodeable = AZ::ScriptValue<EBusHandler*>::StackRead(lua, k_nodeableIndex); // this won't be a BCO, because BCOs won't be necessary in the interpreted mode...most likely
auto nodeable = AZ::ScriptValue<EBusHandler*>::StackRead(lua, k_nodeableIndex);
AZ_Assert(nodeable, "Failed to read EBusHandler");
const char* keyStr = lua_tostring(lua, k_eventNameIndex);
AZ_Assert(keyStr, "Failed to read key string");
const int eventIndex = nodeable->GetEventIndex(keyStr);
AZ_Assert(eventIndex != -1, "Event index was not found for %s-%s", nodeable->GetEBusName().data(), keyStr);
const int eventIndex = lua_tointeger(lua, k_eventNameIndex);
AZ_Assert(eventIndex != -1, "Event index was not found for %s", nodeable->GetEBusName().data());
// install the generic hook for the event
nodeable->HandleEvent(eventIndex);
// Lua: nodeable, string, lambda
@@ -165,7 +159,6 @@ namespace ScriptCanvas
// route the event handling to the lambda on the top of the stack
nodeable->SetExecutionOut(AZ::Crc32(eventIndex), OutInterpretedResult(lua));
// Lua: nodeable, string, lambda
return 0;
}
@@ -70,7 +70,7 @@ namespace ScriptCanvas
void RuntimeComponent::Execute()
{
AZ_PROFILE_SCOPE_DYNAMIC(AZ::Debug::ProfileCategory::ScriptCanvas, "RuntimeComponent::InitializeExecution (%s)", m_runtimeAsset.GetId().ToString<AZStd::string>().c_str());
AZ_PROFILE_SCOPE_DYNAMIC(AZ::Debug::ProfileCategory::ScriptCanvas, "RuntimeComponent::Execute (%s)", m_runtimeAsset.GetId().ToString<AZStd::string>().c_str());
AZ_Assert(m_executionState, "RuntimeComponent::Execute called without an execution state");
SC_EXECUTION_TRACE_GRAPH_ACTIVATED(CreateActivationInfo());
SCRIPT_CANVAS_PERFORMANCE_SCOPE_EXECUTION(m_executionState->GetScriptCanvasId(), m_runtimeAsset.GetId());
@@ -434,7 +434,7 @@ namespace ScriptCanvas
if (!root->HasExplicitUserOutCalls())
{
// there is a single out call, default or not
// there is a single out, default or not
Out out;
if (outCalls.empty())
@@ -468,9 +468,7 @@ namespace ScriptCanvas
}
else
{
// for now, all outs must return all the same output,
// if the UI changes, we'll need to track the output of each individual output
if (outCalls.empty())
if (outCalls.size() < 2)
{
AddError(root->GetNodeId(), root, ScriptCanvas::ParseErrors::NotEnoughBranchesForReturn);
return;
@@ -503,6 +501,9 @@ namespace ScriptCanvas
, returnValueVariable->m_sourceVariableId });
}
AZStd::const_pointer_cast<ExecutionTree>(outCall)->SetOutCallIndex(m_outIndexCount);
++m_outIndexCount;
in.outs.push_back(AZStd::move(out));
}
}
@@ -543,6 +544,8 @@ namespace ScriptCanvas
, returnValueVariable->m_sourceVariableId });
}
AZStd::const_pointer_cast<ExecutionTree>(outCall)->SetOutCallIndex(m_outIndexCount);
++m_outIndexCount;
m_subgraphInterface.AddLatent(AZStd::move(out));
}
@@ -908,6 +911,7 @@ namespace ScriptCanvas
ebusHandling->m_startingAdress = startingAddress;
}
ebusHandling->m_node = &node;
m_ebusHandlingByNode.emplace(&node, ebusHandling);
return true;
}
@@ -3252,6 +3256,15 @@ namespace ScriptCanvas
AZ_Assert(childOutSlot, "null slot in child out slot list");
ExecutionTreePtr internalOut = OpenScope(child, node, childOutSlot);
internalOut->SetNodeable(execution->GetNodeable());
const size_t outIndex = node->GetOutIndex(*childOutSlot);
if (outIndex == std::numeric_limits<size_t>::max())
{
AddError(execution, aznew Internal::ParseError(node->GetEntityId(), AZStd::string::format("Missing internal out key for slot %s", childOutSlot->GetName().c_str())));
return;
}
internalOut->SetOutCallIndex(outIndex);
internalOut->MarkInternalOut();
internalOut->SetSymbol(Symbol::FunctionDefinition);
auto outNameOutcome = node->GetInternalOutKey(*childOutSlot);
@@ -3893,6 +3906,14 @@ namespace ScriptCanvas
auto latentOutKeyOutcome = node.GetLatentOutKey(*slot);
if (latentOutKeyOutcome.IsSuccess())
{
const size_t outIndex = node.GetOutIndex(*slot);
if (outIndex == std::numeric_limits<size_t>::max())
{
AddError(outRoot, aznew Internal::ParseError(node.GetEntityId(), AZStd::string::format("Missing internal out key for slot %s", slot->GetName().c_str())));
return;
}
outRoot->SetOutCallIndex(outIndex);
outRoot->SetName(latentOutKeyOutcome.GetValue().data());
AZStd::const_pointer_cast<NodeableParse>(nodeableParseIter->second)->m_latents.emplace_back(outRoot->GetName(), outRoot);
}
@@ -4622,7 +4643,13 @@ namespace ScriptCanvas
m_userInsThatRequireTopology.clear();
ParseUserOuts();
m_subgraphInterface.Parse();
auto parseOutcome = m_subgraphInterface.Parse();
if (!parseOutcome.IsSuccess())
{
AddError(nullptr, aznew Internal::ParseError(AZ::EntityId(), AZStd::string::format("Subgraph interface failed to parse: %s", parseOutcome.GetError().c_str()).c_str()));
}
}
void AbstractCodeModel::ParseUserIn(ExecutionTreePtr root, const Nodes::Core::FunctionDefinitionNode* nodeling)
@@ -507,6 +507,7 @@ namespace ScriptCanvas
static UserInParseTopologyResult ParseUserInTolopology(size_t nodelingsOutCount, size_t leavesWithoutNodelingsCount);
size_t m_outIndexCount = 0;
ExecutionTreePtr m_start;
AZStd::vector<const Nodes::Core::Start*> m_startNodes;
ScopePtr m_graphScope;
@@ -1057,6 +1057,13 @@ namespace ScriptCanvas
&& azrtti_istypeof<const ScriptCanvas::Nodes::Core::FunctionCallNode*>(execution->GetId().m_node);
}
bool IsUserFunctionCallPure(const ExecutionTreeConstPtr& execution)
{
return (execution->GetSymbol() == Symbol::FunctionCall)
&& azrtti_istypeof<const ScriptCanvas::Nodes::Core::FunctionCallNode*>(execution->GetId().m_node)
&& azrtti_cast<const ScriptCanvas::Nodes::Core::FunctionCallNode*>(execution->GetId().m_node)->IsPure();
}
bool IsUserFunctionDefinition(const ExecutionTreeConstPtr& execution)
{
auto nodeling = azrtti_cast<const ScriptCanvas::Nodes::Core::FunctionDefinitionNode*>(execution->GetId().m_node);
@@ -163,6 +163,8 @@ namespace ScriptCanvas
bool IsUserFunctionCall(const ExecutionTreeConstPtr& execution);
bool IsUserFunctionCallPure(const ExecutionTreeConstPtr& execution);
bool IsUserFunctionDefinition(const ExecutionTreeConstPtr& execution);
const ScriptCanvas::Nodes::Core::FunctionDefinitionNode* IsUserOutNode(const Node* node);
@@ -90,11 +90,11 @@ namespace ScriptCanvas
AZ_CLASS_ALLOCATOR(EBusHandling, AZ::SystemAllocator, 0);
bool m_isAddressed = false;
const Node* m_node = nullptr;
VariableConstPtr m_startingAdress;
AZStd::string m_ebusName;
AZStd::string m_handlerName;
AZStd::vector<AZStd::pair<AZStd::string, ExecutionTreeConstPtr>> m_events;
void Clear();
};
@@ -110,7 +110,7 @@ namespace ScriptCanvas
constexpr const char* k_InitializeStaticsName = "InitializeStatics";
constexpr const char* k_InitializeNodeableOutKeys = "InitializeNodeableOutKeys";
constexpr const char* k_InitializeExecutionOutByRequiredCountName = "InitializeExecutionOutByRequiredCount";
constexpr const char* k_InterpretedConfigurationPerformance = "SCRIPT_CANVAS_GLOBAL_PERFORMANCE";
constexpr const char* k_InterpretedConfigurationRelease = "SCRIPT_CANVAS_GLOBAL_RELEASE";
@@ -260,6 +260,11 @@ namespace ScriptCanvas
return m_nodeable;
}
AZStd::optional<size_t> ExecutionTree::GetOutCallIndex() const
{
return m_outCallIndex != std::numeric_limits<size_t>::max() ? AZStd::optional<size_t>(m_outCallIndex) : AZStd::nullopt;
}
ExecutionTreeConstPtr ExecutionTree::GetParent() const
{
return m_parent;
@@ -559,6 +564,11 @@ namespace ScriptCanvas
m_lexicalScope = lexicalScope;
}
void ExecutionTree::SetOutCallIndex(size_t index)
{
m_outCallIndex = index;
}
void ExecutionTree::SetParent(ExecutionTreePtr parent)
{
m_parent = parent;
@@ -170,6 +170,8 @@ namespace ScriptCanvas
VariableConstPtr GetNodeable() const;
AZStd::optional<size_t> GetOutCallIndex() const;
ExecutionTreeConstPtr GetParent() const;
ExecutionTreeConstPtr GetRoot() const;
@@ -252,6 +254,8 @@ namespace ScriptCanvas
void SetNodeable(VariableConstPtr nodeable);
void SetOutCallIndex(size_t index);
void SetParent(ExecutionTreePtr parent);
void SetScope(ScopePtr scope);
@@ -286,6 +290,8 @@ namespace ScriptCanvas
bool m_hasExplicitUserOutCalls = false;
size_t m_outCallIndex = std::numeric_limits<size_t>::max();
// The node and the activation slot. The execution in, or the event or latent out slot.
ExecutionId m_in;
@@ -66,7 +66,7 @@ namespace ScriptCanvas
break;
}
while (m_timerCounter > m_timerDuration)
while (m_timerCounter >= m_timerDuration)
{
if (!m_isActive)
{
@@ -393,6 +393,11 @@ namespace ScriptCanvas
return false;
}
AZStd::optional<size_t> EBusEventHandler::GetEventIndex(AZStd::string eventName) const
{
return m_handler->GetFunctionIndex(eventName.c_str());
}
const EBusEventEntry* EBusEventHandler::FindEvent(const AZStd::string& name) const
{
AZ::Crc32 key = AZ::Crc32(name.c_str());
@@ -115,6 +115,7 @@ namespace ScriptCanvas
AZ::Outcome<AZStd::string, void> GetFunctionCallName(const Slot* /*slot*/) const override;
bool IsEBusAddressed() const override;
AZStd::optional<size_t> GetEventIndex(AZStd::string eventName) const;
const EBusEventEntry* FindEvent(const AZStd::string& name) const;
AZStd::string GetEBusName() const override;
bool IsAutoConnected() const override;
@@ -548,6 +548,11 @@ namespace ScriptCanvas
return EBusEventHandlerProperty::GetDisconnectSlot(this);
}
AZStd::optional<size_t> ReceiveScriptEvent::GetEventIndex(AZStd::string eventName) const
{
return m_handler->GetFunctionIndex(eventName.c_str());;
}
AZStd::vector<SlotId> ReceiveScriptEvent::GetEventSlotIds() const
{
AZStd::vector<SlotId> eventSlotIds;
@@ -57,6 +57,7 @@ namespace ScriptCanvas
AZ::Outcome<AZStd::string> GetInternalOutKey(const Slot& slot) const override;
const Slot* GetEBusConnectSlot() const override;
const Slot* GetEBusDisconnectSlot() const override;
AZStd::optional<size_t> GetEventIndex(AZStd::string eventName) const override;
AZStd::vector<SlotId> GetEventSlotIds() const override;
AZStd::vector<SlotId> GetNonEventSlotIds() const override;
@@ -136,16 +136,21 @@ namespace ScriptCanvas
}
protected:
size_t GetRequiredOutCount() const override
{
return 2;
}
void Lerp(float t)
{
const t_Operand step = m_start + (m_difference * t);
// make a release note that the lerp complete and tick slot are two different execution threads
ExecutionOut(AZ_CRC_CE("Tick"), step, t);
ExecutionOut(0, step, t);
if (AZ::IsClose(t, 1.0f, AZ::Constants::FloatEpsilon))
{
StopLerp();
ExecutionOut(AZ_CRC_CE("Lerp Complete"));
ExecutionOut(1);
}
}
@@ -22,6 +22,7 @@
#include <ScriptCanvas/Core/ScriptCanvasBus.h>
#include <ScriptCanvas/Variable/VariableCore.h>
#include <ScriptCanvas/PerformanceTracker.h>
#include <ScriptCanvas/Data/DataRegistry.h>
namespace AZ
{
@@ -65,6 +66,8 @@ namespace ScriptCanvas
inline bool IsAnyScriptInterpreted() const { return true; }
AZStd::pair<DataRegistry::Createability, TypeProperties> GetCreatibility(AZ::SerializeContext* serializeContext, AZ::BehaviorClass* behaviorClass);
// SystemRequestBus::Handler...
bool IsScriptUnitTestingInProgress() override;
void MarkScriptUnitTestBegin() override;
@@ -100,7 +103,7 @@ namespace ScriptCanvas
using LockType = AZStd::lock_guard<MutexType>;
AZStd::unordered_map<const void*, BehaviorContextObject*> m_ownedObjectsByAddress;
MutexType m_ownedObjectsByAddressMutex;
int m_infiniteLoopDetectionMaxIterations = 3000;
int m_infiniteLoopDetectionMaxIterations = 1000000;
int m_maxHandlerStackDepth = 50;
static void SafeRegisterPerformanceTracker();
@@ -689,8 +689,16 @@ namespace ScriptCanvas
void GraphToLua::TranslateExecutionTreeUserOutCall(Grammar::ExecutionTreeConstPtr execution)
{
// \todo revisit with per-entity run time storage that keeps execution out calls
m_dotLua.WriteIndented("%s(self, \"%s\"", Grammar::k_NodeableCallInterpretedOut, execution->GetName().data());
auto outCallIndexOptional = execution->GetOutCallIndex();
if (!outCallIndexOptional)
{
AddError(nullptr, aznew Internal::ParseError(execution->GetNodeId(), "Execution did not return required out call index"));
return;
}
const size_t outIndex = *outCallIndexOptional;
m_dotLua.WriteIndented("%s(self, %zu", Grammar::k_NodeableCallInterpretedOut, outIndex);
if (execution->GetInputCount() > 0)
{
@@ -698,7 +706,7 @@ namespace ScriptCanvas
WriteFunctionCallInput(execution);
}
m_dotLua.WriteLine(")");
m_dotLua.WriteLine(") -- %s", execution->GetName().data());
}
void GraphToLua::TranslateFunction(Grammar::ExecutionTreeConstPtr execution, IsNamed lex)
@@ -861,14 +869,23 @@ namespace ScriptCanvas
const bool hasResults = eventThread->HasReturnValues();
AZStd::optional<size_t> eventIndex = ebusHandling->m_node->GetEventIndex(nameAndEventThread.first);
if (!eventIndex)
{
AddError(nullptr, aznew Internal::ParseError(ebusHandling->m_node->GetEntityId(), AZStd::string::format("EBus handler did not return a valid index for event %s", nameAndEventThread.first.c_str())));
return;
}
m_dotLua.WriteNewLine();
m_dotLua.WriteLineIndented("%s(%s%s, '%s',"
m_dotLua.WriteLineIndented("%s(%s%s, %zu, -- %s"
, hasResults ? Grammar::k_EBusHandlerHandleEventResultName : Grammar::k_EBusHandlerHandleEventName
, leftValue.data()
, ebusHandling->m_handlerName.data()
, *eventIndex
, eventThread->GetName().data());
m_dotLua.Indent();
TranslateFunction(eventThread, IsNamed::No);
m_dotLua.WriteLine(")");
@@ -983,14 +1000,7 @@ namespace ScriptCanvas
const auto& outKeys = m_model.GetInterface().GetOutKeys();
if (!outKeys.empty())
{
m_dotLua.WriteIndented("%s(self", Grammar::k_InitializeNodeableOutKeys);
for (auto& key : outKeys)
{
m_dotLua.Write(", %u", AZ::u32(key));
}
m_dotLua.WriteLine(")");
m_dotLua.WriteLineIndented("%s(self, %zu)", Grammar::k_InitializeNodeableOutKeys, outKeys.size());
}
}
else
@@ -1009,15 +1019,26 @@ namespace ScriptCanvas
void GraphToLua::TranslateNodeableOut(Grammar::ExecutionTreeConstPtr execution)
{
auto outCallIndexOptional = execution->GetOutCallIndex();
if (!outCallIndexOptional)
{
AddError(nullptr, aznew Internal::ParseError(execution->GetNodeId(), "Execution did not return required out call index"));
return;
}
const size_t outIndex = *outCallIndexOptional;
// #functions2 remove-execution-out-hash
const auto setExecutionOutName = Grammar::IsUserFunctionDefinition(execution)
? Grammar::k_NodeableSetExecutionOutUserSubgraphName
: execution->HasReturnValues()
? Grammar::k_NodeableSetExecutionOutResultName
: Grammar::k_NodeableSetExecutionOutName;
m_dotLua.WriteLineIndented("%s(self.%s, '%s',"
m_dotLua.WriteLineIndented("%s(self.%s, %zu, -- %s"
, setExecutionOutName
, execution->GetNodeable()->m_name.data()
, execution->GetNodeable()->m_name.data()
, outIndex
, execution->GetName().data());
m_dotLua.Indent();
@@ -1050,7 +1071,6 @@ namespace ScriptCanvas
return;
}
m_dotLua.WriteIndented("function %s.%s(self, ", m_tableName.c_str(), Grammar::k_InitializeStaticsName);
WriteStaticInitializerInput(IsLeadingCommaRequired::No);
m_dotLua.WriteLine(")");
@@ -1078,7 +1098,7 @@ namespace ScriptCanvas
continue;
}
if (variable->m_datum.GetType().GetAZType() == azrtti_typeid<Nodeable>())
if (m_model.IsUserNodeable(variable))
{
auto nodeableName = variable->m_name;
if (nodeableName.starts_with(Grammar::k_memberNamePrefix))
@@ -1104,7 +1124,7 @@ namespace ScriptCanvas
// indexInfo->second.requiresCtorParamsForDependencies
// self.nonLeafDependency = NonLeafDependency.new(executionState, UnpackDependencyArgs(executionState, dependentAssets, 7))
// -- has more dependencies, index, known from compile time, pushes the correct asset further down construction
m_dotLua.WriteLineIndented("%s%s = %s.new(%s, %s(%s, %s, %s))"
m_dotLua.WriteLineIndented("%s%s = %s.new(%s, %s(%s, %s, %zu))"
, leftValue.data()
, variable->m_name.data()
, nodeableName.data()
@@ -1112,7 +1132,7 @@ namespace ScriptCanvas
, Grammar::k_UnpackDependencyConstructionArgsFunctionName
, Grammar::k_executionStateVariableName
, Grammar::k_DependentAssetsArgName
, AZStd::to_string(indexInfo->first).data());
, indexInfo->first);
}
else // vs.
@@ -1120,7 +1140,7 @@ namespace ScriptCanvas
// !indexInfo->second.hasMoreDependencies
// self.leafDependency = LeafDependency.new(executionState, UnpackDependencyArgsLeaf(executionState, dependentAssets, 10))
// -- has NO more dependencies, index, known from compile time
m_dotLua.WriteLineIndented("%s%s = %s.new(%s, %s(%s, %s, %s))"
m_dotLua.WriteLineIndented("%s%s = %s.new(%s, %s(%s, %s, %zu))"
, leftValue.data()
, variable->m_name.data()
, nodeableName.data()
@@ -1128,7 +1148,7 @@ namespace ScriptCanvas
, Grammar::k_UnpackDependencyConstructionArgsLeafFunctionName
, Grammar::k_executionStateVariableName
, Grammar::k_DependentAssetsArgName
, AZStd::to_string(indexInfo->first).data());
, indexInfo->first);
}
}
else
@@ -1158,6 +1178,7 @@ namespace ScriptCanvas
case Grammar::VariableConstructionRequirement::InputNodeable:
m_dotLua.WriteLineIndented("%s:InitializeExecutionState(%s)", variable->m_name.data(), Grammar::k_executionStateVariableName);
m_dotLua.WriteLineIndented("%s:%s()", variable->m_name.c_str(), Grammar::k_InitializeExecutionOutByRequiredCountName);
m_dotLua.WriteLineIndented("%s%s = %s", leftValue.data(), variable->m_name.data(), variable->m_name.data());
break;
@@ -1227,9 +1248,7 @@ namespace ScriptCanvas
void GraphToLua::WriteConstructionDependencyArgs()
{
auto& dependencyArgs = m_model.GetOrderedDependencies().orderedAssetIds;
if (!dependencyArgs.empty())
if (m_model.GetInterface().RequiresConstructionParametersForDependencies())
{
m_dotLua.Write(", %s", Grammar::k_DependentAssetsArgName);
}
@@ -1740,7 +1759,7 @@ namespace ScriptCanvas
size_t GraphToLua::WriteFunctionCallInputThisPointer(Grammar::ExecutionTreeConstPtr execution)
{
if (IsUserFunctionCall(execution) && execution->GetRoot()->IsPure())
if (IsUserFunctionCallPure(execution))
{
m_dotLua.Write("%s", Grammar::k_executionStateVariableName);
@@ -81,6 +81,8 @@ namespace ScriptCanvas
{
return ConstructCustomNodeIdentifier(scriptCanvasNode->RTTI_GetType());
}
return NodeTypeIdentifier(0);
}
NodeTypeIdentifier NodeUtils::ConstructEBusIdentifier(ScriptCanvas::EBusBusId ebusIdentifier)
@@ -43,20 +43,12 @@ namespace ScriptCanvas
{
const char* GetScopeDisplayLabel(Scope scopeType)
{
switch (scopeType)
{
case Scope::Graph:
return "Graph";
case Scope::Function:
return "Function";
default:
return "?";
}
return GraphVariable::s_ScopeNames[static_cast<int>(scopeType)];
}
Scope GetScopeFromLabel(const char* label)
{
if (strcmp("Function", label) == 0)
if (strcmp(GraphVariable::s_ScopeNames[static_cast<int>(VariableFlags::Scope::Function)], label) == 0)
{
return Scope::Function;
}
@@ -71,6 +63,7 @@ namespace ScriptCanvas
case Scope::Graph:
return "Variable is accessible in the entire graph.";
case Scope::Function:
case Scope::FunctionReadOnly:
return "Variable is accessible only in the execution path of the function that defined it";
default:
return "?";
@@ -162,6 +155,14 @@ namespace ScriptCanvas
"From Component"
};
const char* GraphVariable::s_ScopeNames[static_cast<int>(VariableFlags::Scope::COUNT)] =
{
"Graph",
"Function",
"Function",
};
void GraphVariable::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
@@ -197,6 +198,13 @@ namespace ScriptCanvas
return choices;
};
auto scopeChoices = [] {
AZStd::vector< AZStd::pair<VariableFlags::Scope, AZStd::string>> choices;
choices.emplace_back(AZStd::make_pair(VariableFlags::Scope::Graph, s_ScopeNames[0]));
choices.emplace_back(AZStd::make_pair(VariableFlags::Scope::Function, s_ScopeNames[1]));
return choices;
};
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)
@@ -215,8 +223,8 @@ namespace ScriptCanvas
->Attribute(AZ::Edit::Attributes::ChangeNotify, &GraphVariable::OnValueChanged)
->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::Visibility, &GraphVariable::GetScopeControlVisibility)
->Attribute(AZ::Edit::Attributes::GenericValueList, scopeChoices)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &GraphVariable::OnScopeTypedChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &GraphVariable::m_networkProperties, "Network Properties", "Enables whether or not this value should be network synchronized")
@@ -382,6 +390,16 @@ namespace ScriptCanvas
m_inputControlVisibility = inputControlVisibility;
}
AZ::Crc32 GraphVariable::GetScopeControlVisibility() const
{
if (m_scope == VariableFlags::Scope::FunctionReadOnly)
{
return AZ::Edit::PropertyVisibility::Hide;
}
return GetInputControlVisibility();
}
AZ::Crc32 GraphVariable::GetInputControlVisibility() const
{
return m_inputControlVisibility;
@@ -462,6 +480,8 @@ namespace ScriptCanvas
return m_scope == VariableFlags::Scope::Graph;
// All graph variables are in function local scope
case VariableFlags::Scope::Function:
case VariableFlags::Scope::FunctionReadOnly:
return true;
}
@@ -52,8 +52,10 @@ namespace ScriptCanvas
enum class Scope : AZ::u8
{
Graph = 0,
Function = 1,
Graph,
Function,
FunctionReadOnly,
COUNT
};
enum InitialValueSource : AZ::u8
@@ -142,6 +144,7 @@ namespace ScriptCanvas
void SetScriptInputControlVisibility(const AZ::Crc32& inputControlVisibility);
AZ::Crc32 GetInputControlVisibility() const;
AZ::Crc32 GetScopeControlVisibility() const;
AZ::Crc32 GetScriptInputControlVisibility() const;
AZ::Crc32 GetNetworkSettingsVisibility() const;
AZ::Crc32 GetFunctionInputControlVisibility() const;
@@ -181,6 +184,7 @@ namespace ScriptCanvas
int GetSortPriority() const;
static const char* s_InitialValueSourceNames[VariableFlags::InitialValueSource::COUNT];
static const char* s_ScopeNames[static_cast<int>(VariableFlags::Scope::COUNT)];
private:
@@ -225,7 +225,7 @@ namespace ScriptCanvas
}
// #functions2 slot<->variable add this to the graph, using the old datum
AZ::Outcome<VariableId, AZStd::string> GraphVariableManagerComponent::AddVariable(AZStd::string_view name, const Datum& value)
AZ::Outcome<VariableId, AZStd::string> GraphVariableManagerComponent::AddVariable(AZStd::string_view name, const Datum& value, bool functionScope)
{
if (FindVariable(name))
{
@@ -245,6 +245,10 @@ namespace ScriptCanvas
GraphVariable* variable = m_variableData.FindVariable(newId);
variable->SetOwningScriptCanvasId(GetScriptCanvasId());
if (functionScope)
{
variable->SetScope(VariableFlags::Scope::FunctionReadOnly);
}
VariableRequestBus::MultiHandler::BusConnect(GraphScopedVariableId(m_scriptCanvasId, newId));
GraphVariableManagerNotificationBus::Event(GetScriptCanvasId(), &GraphVariableManagerNotifications::OnVariableAddedToGraph, newId, name);
@@ -254,7 +258,7 @@ namespace ScriptCanvas
AZ::Outcome<VariableId, AZStd::string> GraphVariableManagerComponent::AddVariablePair(const AZStd::pair<AZStd::string_view, Datum>& keyValuePair)
{
return AddVariable(keyValuePair.first, keyValuePair.second);
return AddVariable(keyValuePair.first, keyValuePair.second, false);
}
VariableValidationOutcome GraphVariableManagerComponent::IsNameValid(AZStd::string_view varName)
@@ -63,7 +63,7 @@ namespace ScriptCanvas
//// 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> AddVariable(AZStd::string_view name, const Datum& value, bool functionScope) override;
AZ::Outcome<VariableId, AZStd::string> AddVariablePair(const AZStd::pair<AZStd::string_view, Datum>& nameValuePair) override;
VariableValidationOutcome IsNameValid(AZStd::string_view key) override;
@@ -90,7 +90,7 @@ namespace ScriptCanvas
//! 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> AddVariable(AZStd::string_view key, const Datum& value, bool functionScope) = 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;