Merge pull request #6911 from aws-lumberyard-dev/carlitosan-sc-bug-bash-4

Make SC User data slots proper, immutable variable references
This commit is contained in:
carlitosan
2022-01-18 08:41:08 -08:00
committed by GitHub
24 changed files with 2082 additions and 81 deletions
@@ -667,13 +667,12 @@ namespace ScriptCanvasEditor
}
// Now that the slot has a valid type/name, we can actually promote it to a variable
if (PromoteToVariableAction(endpoint) /*&& slot->IsVariableReference()*/)
if (PromoteToVariableAction(endpoint, true))
{
ScriptCanvas::GraphVariable* variable = slot->GetVariable();
if (variable)
{
// functions 2.0 set variable scope to function
if (variable->GetScope() != ScriptCanvas::VariableFlags::Scope::Function)
{
variable->SetScope(ScriptCanvas::VariableFlags::Scope::Function);
@@ -1141,7 +1140,7 @@ namespace ScriptCanvasEditor
{
if (slot->IsVariableReference())
{
return true;
return !slot->IsUserAdded();
}
else
{
@@ -1253,7 +1252,7 @@ namespace ScriptCanvasEditor
return nullptr;
}
if (slot->IsVariableReference())
if (slot->IsVariableReference() && !slot->IsUserAdded())
{
ScriptCanvasVariableReferenceDataInterface* dataInterface = aznew ScriptCanvasVariableReferenceDataInterface(&m_variableDataModel, GetScriptCanvasId(), scriptCanvasNodeId, scriptCanvasSlotId);
GraphCanvas::NodePropertyDisplay* dataDisplay = nullptr;
@@ -2081,20 +2080,20 @@ namespace ScriptCanvasEditor
return false;
}
bool Graph::ConvertSlotToReference(const GraphCanvas::Endpoint& endpoint)
bool Graph::ConvertSlotToReference(const GraphCanvas::Endpoint& endpoint, bool isNewSlot)
{
ScriptCanvas::Endpoint scEndpoint = ConvertToScriptCanvasEndpoint(endpoint);
ScriptCanvas::Node* canvasNode = FindNode(scEndpoint.GetNodeId());
if (canvasNode)
{
return canvasNode->ConvertSlotToReference(scEndpoint.GetSlotId());
return canvasNode->ConvertSlotToReference(scEndpoint.GetSlotId(), isNewSlot);
}
return false;
}
bool Graph::CanConvertSlotToReference(const GraphCanvas::Endpoint& endpoint)
bool Graph::CanConvertSlotToReference(const GraphCanvas::Endpoint& endpoint, bool isNewSlot)
{
ScriptCanvas::Endpoint scEndpoint = ConvertToScriptCanvasEndpoint(endpoint);
ScriptCanvas::Node* canvasNode = FindNode(scEndpoint.GetNodeId());
@@ -2104,7 +2103,7 @@ namespace ScriptCanvasEditor
ScriptCanvas::Slot* slot = canvasNode->GetSlot(scEndpoint.GetSlotId());
if (slot)
{
return slot->CanConvertToReference();
return slot->CanConvertToReference(isNewSlot);
}
}
@@ -2170,7 +2169,7 @@ namespace ScriptCanvasEditor
return handledEvent;
}
bool Graph::CanPromoteToVariable(const GraphCanvas::Endpoint& endpoint) const
bool Graph::CanPromoteToVariable(const GraphCanvas::Endpoint& endpoint, [[maybe_unused]] bool isNewSlot) const
{
ScriptCanvas::Endpoint scriptCanvasEndpoint = ConvertToScriptCanvasEndpoint(endpoint);
auto activeSlot = FindSlot(scriptCanvasEndpoint);
@@ -2189,7 +2188,7 @@ namespace ScriptCanvasEditor
return false;
}
bool Graph::PromoteToVariableAction(const GraphCanvas::Endpoint& endpoint)
bool Graph::PromoteToVariableAction(const GraphCanvas::Endpoint& endpoint, bool isNewSlot)
{
ScriptCanvas::Endpoint scriptCanvasEndpoint = ConvertToScriptCanvasEndpoint(endpoint);
@@ -2282,12 +2281,11 @@ namespace ScriptCanvasEditor
AZ::Outcome<ScriptCanvas::VariableId, AZStd::string> addOutcome;
// #functions2 slot<->variable re-use the activeDatum, send the pointer (actually, all of the source slot information, and make a special conversion)
ScriptCanvas::GraphVariableManagerRequestBus::EventResult(addOutcome, GetScriptCanvasId(), &ScriptCanvas::GraphVariableManagerRequests::AddVariable, variableName, variableDatum, true);
if (addOutcome.IsSuccess())
{
GraphCanvas::DataSlotRequestBus::Event(endpoint.GetSlotId(), &GraphCanvas::DataSlotRequests::ConvertToReference);
GraphCanvas::DataSlotRequestBus::Event(endpoint.GetSlotId(), &GraphCanvas::DataSlotRequests::ConvertToReference, isNewSlot);
activeSlot->SetVariableReference(addOutcome.GetValue());
@@ -2319,7 +2317,7 @@ namespace ScriptCanvasEditor
{
if (!targetSlot->IsVariableReference())
{
GraphCanvas::DataSlotRequestBus::Event(referenceTarget.GetSlotId(), &GraphCanvas::DataSlotRequests::ConvertToReference);
GraphCanvas::DataSlotRequestBus::Event(referenceTarget.GetSlotId(), &GraphCanvas::DataSlotRequests::ConvertToReference, false);
}
if (targetSlot->IsVariableReference())
@@ -2884,7 +2882,7 @@ namespace ScriptCanvasEditor
for (auto graphCanvasEndpoint : referencableEndpoints)
{
GraphCanvas::DataSlotRequestBus::Event(graphCanvasEndpoint.GetSlotId(), &GraphCanvas::DataSlotRequests::ConvertToReference);
GraphCanvas::DataSlotRequestBus::Event(graphCanvasEndpoint.GetSlotId(), &GraphCanvas::DataSlotRequests::ConvertToReference, false);
ScriptCanvas::Endpoint scriptCanvasEndpoint = ConvertToScriptCanvasEndpoint(graphCanvasEndpoint);
@@ -175,12 +175,12 @@ namespace ScriptCanvasEditor
void RemoveSlot(const GraphCanvas::Endpoint& endpoint) override;
bool IsSlotRemovable(const GraphCanvas::Endpoint& endpoint) const override;
bool ConvertSlotToReference(const GraphCanvas::Endpoint& endpoint) override;
bool CanConvertSlotToReference(const GraphCanvas::Endpoint& endpoint) override;
bool ConvertSlotToReference(const GraphCanvas::Endpoint& endpoint, bool isNewSlot = false) override;
bool CanConvertSlotToReference(const GraphCanvas::Endpoint& endpoint, bool isNewSlot = false) override;
GraphCanvas::CanHandleMimeEventOutcome CanHandleReferenceMimeEvent(const GraphCanvas::Endpoint& endpoint, const QMimeData* mimeData) override;
bool HandleReferenceMimeEvent(const GraphCanvas::Endpoint& endpoint, const QMimeData* mimeData) override;
bool CanPromoteToVariable(const GraphCanvas::Endpoint& endpoint) const override;
bool PromoteToVariableAction(const GraphCanvas::Endpoint& endpoint) override;
bool CanPromoteToVariable(const GraphCanvas::Endpoint& endpoint, bool isNewSlot = false) const override;
bool PromoteToVariableAction(const GraphCanvas::Endpoint& endpoint, bool isNewSlot = false) override;
bool SynchronizeReferences(const GraphCanvas::Endpoint& sourceEndpoint, const GraphCanvas::Endpoint& targetEndpoint) override;
bool ConvertSlotToValue(const GraphCanvas::Endpoint& endpoint) override;
@@ -3873,7 +3873,13 @@ namespace ScriptCanvasEditor
contextMenu.AddMenuAction(aznew ConvertReferenceToVariableNodeAction(&contextMenu));
contextMenu.AddMenuAction(aznew ExposeSlotMenuAction(&contextMenu));
contextMenu.AddMenuAction(aznew CreateAzEventHandlerSlotMenuAction(&contextMenu));
contextMenu.AddMenuAction(aznew SetDataSlotTypeMenuAction(&contextMenu));
auto setSlotTypeAction = aznew SetDataSlotTypeMenuAction(&contextMenu);
// Changing slot type is disabled temporarily because now that that user data slots are correctly coordinated with their reference
// variables, their type cannot be changed. The next change will allow all variables to change their type post creation, and then
// that will allow this action to be enabled.
setSlotTypeAction->setEnabled(false);
contextMenu.AddMenuAction(setSlotTypeAction);
return HandleContextMenu(contextMenu, slotId, screenPoint, scenePoint);
}
@@ -516,7 +516,7 @@ namespace ScriptCanvasEditor
GraphCanvas::SlotRequestBus::EventResult(endpoint, slotId2, &GraphCanvas::SlotRequests::GetEndpoint);
bool promotedElement = false;
GraphCanvas::GraphModelRequestBus::EventResult(promotedElement, graphId2, &GraphCanvas::GraphModelRequests::PromoteToVariableAction, endpoint);
GraphCanvas::GraphModelRequestBus::EventResult(promotedElement, graphId2, &GraphCanvas::GraphModelRequests::PromoteToVariableAction, endpoint, false);
if (promotedElement)
{
@@ -100,12 +100,18 @@ namespace ScriptCanvas
{
RuntimeAsset* runtimeAsset = asset.GetAs<RuntimeAsset>();
AZ_Assert(runtimeAsset, "This should be a Script Canvas runtime asset, as this is the only type we process!");
if (runtimeAsset && m_serializeContext)
{
stream->Seek(0U, AZ::IO::GenericStream::ST_SEEK_BEGIN);
bool loadSuccess = AZ::Utils::LoadObjectFromStreamInPlace(*stream, runtimeAsset->m_runtimeData, m_serializeContext, AZ::ObjectStream::FilterDescriptor(assetLoadFilterCB));
const bool loadSuccess = AZ::Utils::LoadObjectFromStreamInPlace(*stream, runtimeAsset->m_runtimeData
, m_serializeContext, AZ::ObjectStream::FilterDescriptor(assetLoadFilterCB));
AZ_Error("ScriptCanvas", loadSuccess, "ScriptCanvas failed to load runtime asset: %s - %s"
, asset.GetHint().c_str(), asset.GetId().ToString<AZStd::string>().c_str());
return loadSuccess ? AZ::Data::AssetHandler::LoadResult::LoadComplete : AZ::Data::AssetHandler::LoadResult::Error;
}
return AZ::Data::AssetHandler::LoadResult::Error;
}
@@ -2577,11 +2577,11 @@ namespace ScriptCanvas
}
}
bool Node::ConvertSlotToReference(const SlotId& slotId)
bool Node::ConvertSlotToReference(const SlotId& slotId, bool isNewSlot)
{
Slot* slot = GetSlot(slotId);
if (slot && slot->ConvertToReference())
if (slot && slot->ConvertToReference(isNewSlot))
{
InitializeVariableReference((*slot), {});
return true;
@@ -498,7 +498,7 @@ namespace ScriptCanvas
void SanityCheckDynamicDisplay();
void SanityCheckDynamicDisplay(ExploredDynamicGroupCache& exploredGroupCache);
bool ConvertSlotToReference(const SlotId& slotId);
bool ConvertSlotToReference(const SlotId& slotId, bool isNewSlot = false);
bool ConvertSlotToValue(const SlotId& slotId);
NamedEndpoint CreateNamedEndpoint(SlotId slotId) const;
@@ -460,14 +460,14 @@ namespace ScriptCanvas
&& GetDataType() != Data::Type::BehaviorContextObject(GraphScopedVariableId::TYPEINFO_Uuid());
}
bool Slot::CanConvertToReference() const
{
return !m_isUserAdded && CanConvertTypes() && !m_isVariableReference && !m_node->HasConnectedNodes((*this));
bool Slot::CanConvertToReference(bool isNewSlot) const
{
return (!m_isUserAdded || isNewSlot) && CanConvertTypes() && !m_isVariableReference && !m_node->HasConnectedNodes((*this));
}
bool Slot::ConvertToReference()
bool Slot::ConvertToReference(bool isNewSlot)
{
if (CanConvertToReference())
if (CanConvertToReference(isNewSlot))
{
m_isVariableReference = true;
@@ -147,8 +147,8 @@ namespace ScriptCanvas
bool CanConvertToValue() const;
bool ConvertToValue();
bool CanConvertToReference() const;
bool ConvertToReference();
bool CanConvertToReference(bool isNewSlot = false) const;
bool ConvertToReference(bool isNewSlot = false);
void SetVariableReference(const VariableId& variableId);
const VariableId& GetVariableReference() const;
GraphVariable* GetVariable() const;
@@ -240,7 +240,6 @@ namespace ScriptCanvas
// #functions2 slot<->variable consider getting all variables from the UX variable manager, or from the ACM and looking them up in the variable manager for ordering
m_sourceVariableByDatum.insert(AZStd::make_pair(datum, &variablePair.second));
}
}
for (auto& sourceVariable : sortedVariables)
@@ -1714,6 +1713,7 @@ namespace ScriptCanvas
auto iter = m_inputVariableByNodelingInSlot.find(input);
if (iter != m_inputVariableByNodelingInSlot.end())
{
// #sc_user_slot_variable_ux don't add variable name if not necessary
VariablePtr variable = iter->second;
const Slot* slot = iter->first;
variable->m_name = call->ModScope()->AddVariableName(slot->GetName());
@@ -4644,35 +4644,59 @@ namespace ScriptCanvas
void AbstractCodeModel::ParseNodelingVariables(const Node& node, NodelingType nodelingType)
{
// #functions2 slot<->variable adjust once datums are more coordinated
auto createVariablesSlots = [&](AZStd::unordered_map<const Slot*, VariablePtr>& variablesBySlots, const AZStd::vector<const Slot*>& slots, bool slotHasDatum)
// This function accounts for all the ways users have been able to introduce input/output data in their SC function definitions.
// They have been able to create slots, variables, or both. This function reads the datums to create the correct ACM
// variable per required SC user variable. It uses slots as the key, and checks datums in the SC variable list for possible
// matches.
auto createVariablesSlots = [&](AZStd::unordered_map<const Slot*, VariablePtr>& variablesBySlots, const AZStd::vector<const Slot*>& slots, bool errorOnMissingDatum)
{
for (const auto& slot : slots)
{
auto variable = AZStd::make_shared<Variable>();
auto variableDatum = slot->FindDatum();
bool initializeDatum = true;
if (slotHasDatum)
if (variableDatum)
{
auto variableDatum = slot->FindDatum();
if (!variableDatum)
{
AddError(nullptr, aznew Internal::ParseError(node.GetEntityId(), AZStd::string::format("Datum missing from Slot %s on Node %s", slot->GetName().data(), node.GetNodeName().c_str())));
return;
}
initializeDatum = false;
}
else if (errorOnMissingDatum)
{
AddError(nullptr, aznew Internal::ParseError(node.GetEntityId(), AZStd::string::format("Datum missing from Slot %s on Node %s", slot->GetName().data(), node.GetNodeName().c_str())));
return;
}
// #functions2 slot<->variable consider getting all variables from the UX variable manager, or from the ACM and looking them up in the variable manager for ordering
// auto iter = m_sourceVariableByDatum.find(variableDatum);
// if (iter == m_sourceVariableByDatum.end())
// {
// AddError(nullptr, aznew Internal::ParseError(node.GetEntityId(), AZStd::string::format("Datum missing from Slot %s on Node %s", slot->GetName().data(), node.GetNodeName().c_str())));
// return;
// }
// variable->m_sourceVariableId = iter->second->GetVariableId();
// find the other variable
auto iter = m_sourceVariableByDatum.find(variableDatum);
if (iter != m_sourceVariableByDatum.end())
{
initializeDatum = false;
}
else if (!variableDatum && errorOnMissingDatum)
{
AddError(nullptr, aznew Internal::ParseError(node.GetEntityId(), AZStd::string::format("Datum missing from Slot %s on Node %s", slot->GetName().data(), node.GetNodeName().c_str())));
return;
}
VariablePtr premadeVariable = iter != m_sourceVariableByDatum.end()
? AZStd::const_pointer_cast<Variable>(FindVariable(iter->second->GetVariableId()))
: VariablePtr();
if (premadeVariable)
{
initializeDatum = false;
variable = premadeVariable;
}
variable->m_sourceSlotId = slot->GetId();
if (!premadeVariable && variableDatum)
{
variable->m_datum = *variableDatum;
}
else
if (initializeDatum)
{
// make a new datum and a source slot id and all that
variable->m_datum.SetType(slot->GetDataType());
}
@@ -4680,7 +4704,11 @@ namespace ScriptCanvas
variable->m_sourceSlotId = slot->GetId();
variable->m_isFromFunctionDefinitionSlot = true;
variablesBySlots.insert({ slot, variable });
m_variables.push_back(variable);
if (!premadeVariable)
{
m_variables.push_back(variable);
}
}
};
@@ -220,7 +220,6 @@ namespace ScriptCanvas
return AZ::Success(newId);
}
// #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, bool functionScope)
{
if (FindVariable(name))