diff --git a/Code/Framework/AzCore/AzCore/Script/ScriptContext.cpp b/Code/Framework/AzCore/AzCore/Script/ScriptContext.cpp index 45f7876993..841387f14d 100644 --- a/Code/Framework/AzCore/AzCore/Script/ScriptContext.cpp +++ b/Code/Framework/AzCore/AzCore/Script/ScriptContext.cpp @@ -5073,13 +5073,26 @@ LUA_API const Node* lua_getDummyNode() // Check all constructors if they have use ScriptDataContext and if so choose this one if (!customConstructorMethod) { + int overrideIndex = -1; + AZ::AttributeReader(nullptr, FindAttribute + ( Script::Attributes::DefaultConstructorOverrideIndex, behaviorClass->m_attributes)).Read(overrideIndex); + + int methodIndex = 0; for (BehaviorMethod* method : behaviorClass->m_constructors) { + if (methodIndex == overrideIndex) + { + customConstructorMethod = method; + break; + } + if (method->GetNumArguments() && method->GetArgument(method->GetNumArguments() - 1)->m_typeId == AZ::AzTypeInfo::Uuid()) { customConstructorMethod = method; break; } + + ++methodIndex; } } diff --git a/Code/Framework/AzCore/AzCore/Script/ScriptContextAttributes.h b/Code/Framework/AzCore/AzCore/Script/ScriptContextAttributes.h index 9807f0af39..e238289ef5 100644 --- a/Code/Framework/AzCore/AzCore/Script/ScriptContextAttributes.h +++ b/Code/Framework/AzCore/AzCore/Script/ScriptContextAttributes.h @@ -21,6 +21,7 @@ namespace AZ static constexpr AZ::Crc32 ClassNameOverride = AZ_CRC_CE("ScriptClassNameOverride"); ///< Provide a custom name for script reflection, that doesn't match the behavior Context name static constexpr AZ::Crc32 MethodOverride = AZ_CRC_CE("ScriptFunctionOverride"); ///< Use a custom function in the attribute instead of the function static constexpr AZ::Crc32 ConstructorOverride = AZ_CRC_CE("ConstructorOverride"); ///< You can provide a custom constructor to be called when created from Lua script + static constexpr AZ::Crc32 DefaultConstructorOverrideIndex = AZ_CRC_CE("DefaultConstructorOverrideIndex"); ///< Use a different class constructor as the default constructor in Lua static constexpr AZ::Crc32 EventHandlerCreationFunction = AZ_CRC_CE("EventHandlerCreationFunction"); ///< helps create a handler for any script target so that script functions can be used for AZ::Event signals static constexpr AZ::Crc32 GenericConstructorOverride = AZ_CRC_CE("GenericConstructorOverride"); ///< You can provide a custom constructor to be called when creating a script static constexpr AZ::Crc32 ReaderWriterOverride = AZ_CRC_CE("ReaderWriterOverride"); ///< paired with \ref ScriptContext::CustomReaderWriter allows you to customize read/write to Lua VM diff --git a/Code/Framework/AzCore/AzCore/Serialization/EditContextConstants.inl b/Code/Framework/AzCore/AzCore/Serialization/EditContextConstants.inl index 4f8c67f058..27f27dd6dd 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/EditContextConstants.inl +++ b/Code/Framework/AzCore/AzCore/Serialization/EditContextConstants.inl @@ -133,6 +133,8 @@ namespace AZ const static AZ::Crc32 AllowClearAsset = AZ_CRC("AllowClearAsset", 0x24827182); // Show the name of the asset that was produced from the source asset const static AZ::Crc32 ShowProductAssetFileName = AZ_CRC("ShowProductAssetFileName"); + //! Regular expression pattern filter for source files + const static AZ::Crc32 SourceAssetFilterPattern = AZ_CRC_CE("SourceAssetFilterPattern"); //! Component icon attributes const static AZ::Crc32 Icon = AZ_CRC("Icon", 0x659429db); diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.cpp index 7309955a1c..4f5657a328 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.cpp @@ -204,6 +204,22 @@ namespace AZ // BaseJsonSerializer // + JsonSerializationResult::Result BaseJsonSerializer::Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, + JsonDeserializerContext& context) + { + JsonSerializationResult::ResultCode result(JsonSerializationResult::Tasks::ReadField); + result.Combine(ContinueLoading(outputValue, outputValueTypeId, inputValue, context, ContinuationFlags::IgnoreTypeSerializer)); + return context.Report(result, "Ignoring custom serialization during load"); + } + + JsonSerializationResult::Result BaseJsonSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, + const Uuid& valueTypeId, JsonSerializerContext& context) + { + JsonSerializationResult::ResultCode result(JsonSerializationResult::Tasks::WriteValue); + result.Combine(ContinueStoring(outputValue, inputValue, defaultValue, valueTypeId, context, ContinuationFlags::IgnoreTypeSerializer)); + return context.Report(result, "Ignoring custom serialization during store"); + } + BaseJsonSerializer::OperationFlags BaseJsonSerializer::GetOperationsFlags() const { return OperationFlags::None; diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.h b/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.h index 7d2af01c16..4e8f545367 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.h +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.h @@ -180,13 +180,16 @@ namespace AZ //! Transforms the data from the rapidjson Value to outputValue, if the conversion is possible and supported. //! The serializer is responsible for casting to the proper type and safely writing to the outputValue memory. + //! \note The default implementation is to load the object ignoring a custom serializers for the type, which allows for custom serializers + //! to modify the object after all default loading has occurred. virtual JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, - JsonDeserializerContext& context) = 0; + JsonDeserializerContext& context); //! Write the input value to a rapidjson value if the default value is not null and doesn't match the input value, otherwise //! an error is returned and sets the rapidjson value to a null value. + //! \note The default implementation is to store the object ignoring custom serializers. virtual JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, - const Uuid& valueTypeId, JsonSerializerContext& context) = 0; + const Uuid& valueTypeId, JsonSerializerContext& context); //! Returns the operation flags which tells the Json Serialization how this custom json serializer can be used. virtual OperationFlags GetOperationsFlags() const; diff --git a/Code/Framework/AzCore/AzCore/Utils/Utils.cpp b/Code/Framework/AzCore/AzCore/Utils/Utils.cpp index 12c6473905..1623aca56b 100644 --- a/Code/Framework/AzCore/AzCore/Utils/Utils.cpp +++ b/Code/Framework/AzCore/AzCore/Utils/Utils.cpp @@ -165,13 +165,12 @@ namespace AZ::Utils } Container fileContent; - fileContent.resize(length); + fileContent.resize_no_construct(length); AZ::IO::SizeType bytesRead = file.Read(length, fileContent.data()); file.Close(); // Resize again just in case bytesRead is less than length for some reason - fileContent.resize(bytesRead); - + fileContent.resize_no_construct(bytesRead); return AZ::Success(AZStd::move(fileContent)); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp index eae8ec2a1e..4e3b8ee745 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp @@ -99,6 +99,18 @@ namespace AzToolsFramework } } + if (selection.GetSelectedAssetIds().empty()) + { + for (auto& filePath : selection.GetSelectedFilePaths()) + { + if (!filePath.empty()) + { + selectedAsset = true; + m_ui->m_assetBrowserTreeViewWidget->SelectFileAtPath(filePath); + } + } + } + if (!selectedAsset) { m_ui->m_assetBrowserTreeViewWidget->SelectFolder(selection.GetDefaultDirectory()); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.cpp index 3547cf57b3..2fbdcaf40b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.cpp @@ -10,18 +10,24 @@ #include #include +#if !defined(Q_MOC_RUN) +AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") +#include +AZ_POP_DISABLE_WARNING +#endif + namespace AzToolsFramework { namespace AssetBrowser { namespace { - FilterConstType ProductsNoFoldersFilter() + FilterConstType EntryTypeNoFoldersFilter(AssetBrowserEntry::AssetEntryType entryType = AssetBrowserEntry::AssetEntryType::Product) { - EntryTypeFilter* productFilter = new EntryTypeFilter(); - productFilter->SetEntryType(AssetBrowserEntry::AssetEntryType::Product); + EntryTypeFilter* entryTypeFilter = new EntryTypeFilter(); + entryTypeFilter->SetEntryType(entryType); // in case entry is a source or folder, it may still contain relevant product - productFilter->SetFilterPropagation(AssetBrowserEntryFilter::PropagateDirection::Down); + entryTypeFilter->SetFilterPropagation(AssetBrowserEntryFilter::PropagateDirection::Down); EntryTypeFilter* foldersFilter = new EntryTypeFilter(); foldersFilter->SetEntryType(AssetBrowserEntry::AssetEntryType::Folder); @@ -30,7 +36,7 @@ namespace AzToolsFramework noFoldersFilter->SetFilter(FilterConstType(foldersFilter)); CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND); - compFilter->AddFilter(FilterConstType(productFilter)); + compFilter->AddFilter(FilterConstType(entryTypeFilter)); compFilter->AddFilter(FilterConstType(noFoldersFilter)); return FilterConstType(compFilter); @@ -79,15 +85,39 @@ namespace AzToolsFramework void AssetSelectionModel::SetSelectedAssetIds(const AZStd::vector& selectedAssetIds) { + m_selectedFilePaths.clear(); + m_selectedAssetIds = selectedAssetIds; } void AssetSelectionModel::SetSelectedAssetId(const AZ::Data::AssetId& selectedAssetId) { + m_selectedFilePaths.clear(); + m_selectedAssetIds.clear(); m_selectedAssetIds.push_back(selectedAssetId); } + const AZStd::vector& AssetSelectionModel::GetSelectedFilePaths() const + { + return m_selectedFilePaths; + } + + void AssetSelectionModel::SetSelectedFilePaths(const AZStd::vector& selectedFilePaths) + { + m_selectedAssetIds.clear(); + + m_selectedFilePaths = selectedFilePaths; + } + + void AssetSelectionModel::SetSelectedFilePath(const AZStd::string& selectedFilePath) + { + m_selectedAssetIds.clear(); + + m_selectedFilePaths.clear(); + m_selectedFilePaths.push_back(selectedFilePath); + } + void AssetSelectionModel::SetDefaultDirectory(AZStd::string_view defaultDirectory) { m_defaultDirectory = defaultDirectory; @@ -136,7 +166,7 @@ namespace AzToolsFramework CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND); compFilter->AddFilter(assetTypeFilterPtr); - compFilter->AddFilter(ProductsNoFoldersFilter()); + compFilter->AddFilter(EntryTypeNoFoldersFilter()); selection.SetSelectionFilter(FilterConstType(compFilter)); selection.SetMultiselect(multiselect); @@ -169,7 +199,7 @@ namespace AzToolsFramework CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND); compFilter->AddFilter(anyAssetTypeFilterPtr); - compFilter->AddFilter(ProductsNoFoldersFilter()); + compFilter->AddFilter(EntryTypeNoFoldersFilter()); selection.SetSelectionFilter(FilterConstType(compFilter)); selection.SetMultiselect(multiselect); @@ -190,7 +220,28 @@ namespace AzToolsFramework CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND); compFilter->AddFilter(assetGroupFilterPtr); - compFilter->AddFilter(ProductsNoFoldersFilter()); + compFilter->AddFilter(EntryTypeNoFoldersFilter()); + + selection.SetSelectionFilter(FilterConstType(compFilter)); + selection.SetMultiselect(multiselect); + + return selection; + } + + AssetSelectionModel AssetSelectionModel::SourceAssetTypeSelection(const QString& pattern, bool multiselect) + { + AssetSelectionModel selection; + + RegExpFilter* patternFilter = new RegExpFilter(); + patternFilter->SetFilterPattern(pattern); + patternFilter->SetFilterPropagation(AssetBrowserEntryFilter::PropagateDirection::Down); + auto patternFilterPtr = FilterConstType(patternFilter); + + selection.SetDisplayFilter(patternFilterPtr); + + CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND); + compFilter->AddFilter(patternFilterPtr); + compFilter->AddFilter(EntryTypeNoFoldersFilter(AssetBrowserEntry::AssetEntryType::Source)); selection.SetSelectionFilter(FilterConstType(compFilter)); selection.SetMultiselect(multiselect); @@ -204,7 +255,7 @@ namespace AzToolsFramework CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::OR); selection.SetDisplayFilter(FilterConstType(compFilter)); - selection.SetSelectionFilter(ProductsNoFoldersFilter()); + selection.SetSelectionFilter(EntryTypeNoFoldersFilter()); selection.SetMultiselect(multiselect); return selection; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.h index 4036c166ac..241c896123 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.h @@ -44,6 +44,10 @@ namespace AzToolsFramework void SetSelectedAssetIds(const AZStd::vector& selectedAssetIds); void SetSelectedAssetId(const AZ::Data::AssetId& selectedAssetId); + const AZStd::vector& GetSelectedFilePaths() const; + void SetSelectedFilePaths(const AZStd::vector& selectedFilePaths); + void SetSelectedFilePath(const AZStd::string& selectedFilePath); + void SetDefaultDirectory(AZStd::string_view defaultDirectory); AZStd::string_view GetDefaultDirectory() const; @@ -60,6 +64,7 @@ namespace AzToolsFramework static AssetSelectionModel AssetTypeSelection(const char* assetTypeName, bool multiselect = false); static AssetSelectionModel AssetTypesSelection(const AZStd::vector& assetTypes, bool multiselect = false); static AssetSelectionModel AssetGroupSelection(const char* group, bool multiselect = false); + static AssetSelectionModel SourceAssetTypeSelection(const QString& pattern, bool multiselect = false); static AssetSelectionModel EverythingSelection(bool multiselect = false); private: @@ -68,8 +73,12 @@ namespace AzToolsFramework // some entries like folder should always be displayed, but not always selectable, thus 2 separate filters FilterConstType m_selectionFilter; FilterConstType m_displayFilter; - + + //! Selection can be based on asset ids (for products), or file paths (for sources) + //! These are mututally exclusive AZStd::vector m_selectedAssetIds; + AZStd::vector m_selectedFilePaths; + AZStd::vector m_results; AZStd::string m_defaultDirectory; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.cpp index 3f267dedd0..d617638632 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.cpp @@ -251,6 +251,40 @@ namespace AzToolsFramework return false; } + ////////////////////////////////////////////////////////////////////////// + // RegExpFilter + ////////////////////////////////////////////////////////////////////////// + RegExpFilter::RegExpFilter() + : m_filterPattern("") + { + } + + void RegExpFilter::SetFilterPattern(const QString& filterPattern) + { + m_filterPattern = filterPattern; + Q_EMIT updatedSignal(); + } + + QString RegExpFilter::GetNameInternal() const + { + return m_filterPattern; + } + + bool RegExpFilter::MatchInternal(const AssetBrowserEntry* entry) const + { + // no filter pattern matches any asset + if (m_filterPattern.isEmpty()) + { + return true; + } + + // entry's name matches regular expression pattern + QRegExp regExp(m_filterPattern); + regExp.setPatternSyntax(QRegExp::Wildcard); + + return regExp.exactMatch(entry->GetDisplayName()); + } + ////////////////////////////////////////////////////////////////////////// // AssetTypeFilter ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.h index 5819ae92d7..94f47e0599 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.h @@ -115,6 +115,28 @@ namespace AzToolsFramework QString m_filterString; }; + ////////////////////////////////////////////////////////////////////////// + // RegExpFilter + ////////////////////////////////////////////////////////////////////////// + //! RegExpFilter filters assets based on a regular expression pattern + class RegExpFilter + : public AssetBrowserEntryFilter + { + Q_OBJECT + public: + RegExpFilter(); + ~RegExpFilter() override = default; + + void SetFilterPattern(const QString& filterPattern); + + protected: + QString GetNameInternal() const override; + bool MatchInternal(const AssetBrowserEntry* entry) const override; + + private: + QString m_filterPattern; + }; + ////////////////////////////////////////////////////////////////////////// // AssetTypeFilter ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.cpp index 3e5b41ebeb..40f3b7063e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.cpp @@ -39,7 +39,12 @@ namespace AzToolsFramework typeFilter->SetAssetType(filterType); typeFilter->SetFilterPropagation(AssetBrowserEntryFilter::PropagateDirection::Down); - m_assetBrowserFilterModel->SetFilter(FilterConstType(typeFilter)); + SetFilter(FilterConstType(typeFilter)); + } + + void AssetCompleterModel::SetFilter(FilterConstType filter) + { + m_assetBrowserFilterModel->SetFilter(filter); RefreshAssetList(); } @@ -120,9 +125,6 @@ namespace AzToolsFramework int rows = m_assetBrowserFilterModel->rowCount(index); if (rows == 0) { - if (index != QModelIndex()) { - AZ_Error("AssetCompleterModel", false, "No children detected in FetchResources()"); - } return; } @@ -131,7 +133,7 @@ namespace AzToolsFramework QModelIndex childIndex = m_assetBrowserFilterModel->index(i, 0, index); AssetBrowserEntry* childEntry = GetAssetEntry(m_assetBrowserFilterModel->mapToSource(childIndex)); - if (childEntry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Product) + if (childEntry->GetEntryType() == m_entryType) { ProductAssetBrowserEntry* productEntry = static_cast(childEntry); AZStd::string assetName; @@ -167,7 +169,6 @@ namespace AzToolsFramework return m_assets[index.row()].m_displayName; } - const AZ::Data::AssetId AssetCompleterModel::GetAssetIdFromIndex(const QModelIndex& index) { if (!index.isValid()) @@ -177,4 +178,19 @@ namespace AzToolsFramework return m_assets[index.row()].m_assetId; } + + const AZStd::string_view AssetCompleterModel::GetPathFromIndex(const QModelIndex& index) + { + if (!index.isValid()) + { + return ""; + } + + return m_assets[index.row()].m_path; + } + + void AssetCompleterModel::SetFetchEntryType(AssetBrowserEntry::AssetEntryType entryType) + { + m_entryType = entryType; + } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.h index 55a6db8589..4596d70657 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.h @@ -32,6 +32,7 @@ namespace AzToolsFramework QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; void SetFilter(AZ::Data::AssetType filterType); + void SetFilter(FilterConstType filter); void RefreshAssetList(); void SearchStringHighlight(QString searchString); @@ -39,6 +40,9 @@ namespace AzToolsFramework const AZStd::string_view GetNameFromIndex(const QModelIndex& index); const AZ::Data::AssetId GetAssetIdFromIndex(const QModelIndex& index); + const AZStd::string_view GetPathFromIndex(const QModelIndex& index); + + void SetFetchEntryType(AssetBrowserEntry::AssetEntryType entryType); private: struct AssetItem @@ -57,6 +61,8 @@ namespace AzToolsFramework AZStd::vector m_assets; //! String that will be highlighted in the suggestions QString m_highlightString; + + AssetBrowserEntry::AssetEntryType m_entryType = AssetBrowserEntry::AssetEntryType::Product; }; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp index 384b384a23..16270ac8c7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp @@ -1288,7 +1288,7 @@ namespace AzToolsFramework return newCtrl; } - void AssetPropertyHandlerDefault::ConsumeAttribute(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName) + void AssetPropertyHandlerDefault::ConsumeAttributeInternal(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName) { (void)debugName; @@ -1487,6 +1487,11 @@ namespace AzToolsFramework } } + void AssetPropertyHandlerDefault::ConsumeAttribute(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName) + { + ConsumeAttributeInternal(GUI, attrib, attrValue, debugName); + } + void AssetPropertyHandlerDefault::WriteGUIValuesIntoProperty(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node) { (void)index; @@ -1629,8 +1634,8 @@ namespace AzToolsFramework void RegisterAssetPropertyHandler() { - EBUS_EVENT(PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew AssetPropertyHandlerDefault()); - EBUS_EVENT(PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew SimpleAssetPropertyHandlerDefault()); + PropertyTypeRegistrationMessages::Bus::Broadcast(&PropertyTypeRegistrationMessages::RegisterPropertyType, aznew AssetPropertyHandlerDefault()); + PropertyTypeRegistrationMessages::Bus::Broadcast(&PropertyTypeRegistrationMessages::RegisterPropertyType, aznew SimpleAssetPropertyHandlerDefault()); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx index 58ddbb967e..d6ff1b8de6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx @@ -175,10 +175,11 @@ namespace AzToolsFramework virtual void SetFolderSelection(const AZStd::string& /* folderPath */) {} virtual void ClearAssetInternal(); - void ConfigureAutocompleter(); + virtual void ConfigureAutocompleter(); void RefreshAutocompleter(); void EnableAutocompleter(); void DisableAutocompleter(); + const QModelIndex GetSourceIndex(const QModelIndex& index); void HandleFieldClear(); AZStd::string AddDefaultSuffix(const AZStd::string& filename); @@ -235,20 +236,19 @@ namespace AzToolsFramework void SetSelectedAssetID(const AZ::Data::AssetId& newID, const AZ::Data::AssetType& newType); void SetCurrentAssetHint(const AZStd::string& hint); void SetDefaultAssetID(const AZ::Data::AssetId& defaultID); - void PopupAssetPicker(); + virtual void PopupAssetPicker(); void OnClearButtonClicked(); void UpdateAssetDisplay(); void OnLineEditFocus(bool focus); virtual void OnEditButtonClicked(); void OnThumbnailClicked(); void OnCompletionModelReset(); - void OnAutocomplete(const QModelIndex& index); + virtual void OnAutocomplete(const QModelIndex& index); void OnTextChange(const QString& text); void OnReturnPressed(); void ShowContextMenu(const QPoint& pos); private: - const QModelIndex GetSourceIndex(const QModelIndex& index); void UpdateThumbnail(); }; @@ -270,7 +270,8 @@ namespace AzToolsFramework virtual void UpdateWidgetInternalTabbing(PropertyAssetCtrl* widget) override { widget->UpdateTabOrder(); } virtual QWidget* CreateGUI(QWidget* pParent) override; - virtual void ConsumeAttribute(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName) override; + static void ConsumeAttributeInternal(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName); + void ConsumeAttribute(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName) override; virtual void WriteGUIValuesIntoProperty(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node) override; virtual bool ReadValuesIntoGUI(size_t index, PropertyAssetCtrl* GUI, const property_t& instance, InstanceDataNode* node) override; }; diff --git a/Gems/GraphCanvas/Code/Source/Components/SceneComponent.cpp b/Gems/GraphCanvas/Code/Source/Components/SceneComponent.cpp index 52e7892364..e821ea9be2 100644 --- a/Gems/GraphCanvas/Code/Source/Components/SceneComponent.cpp +++ b/Gems/GraphCanvas/Code/Source/Components/SceneComponent.cpp @@ -669,6 +669,7 @@ namespace GraphCanvas { GeometryNotificationBus::Handler::BusDisconnect(); SceneNotificationBus::Handler::BusDisconnect(); + AZ::SystemTickBus::Handler::BusDisconnect(); } void GestureSceneHelper::TrackElement(const AZ::EntityId& elementId) diff --git a/Gems/GraphCanvas/Code/Source/Translation/TranslationAsset.cpp b/Gems/GraphCanvas/Code/Source/Translation/TranslationAsset.cpp index a461866c46..3b026b4579 100644 --- a/Gems/GraphCanvas/Code/Source/Translation/TranslationAsset.cpp +++ b/Gems/GraphCanvas/Code/Source/Translation/TranslationAsset.cpp @@ -195,7 +195,7 @@ namespace GraphCanvas } else { - AZ_Error("TranslationAsset", false, "Serialization of the TranslationFormat failed for: %s", asset.GetHint().c_str()); + AZ_Warning("TranslationAsset", false, "Serialization of the TranslationFormat failed for: %s", asset.GetHint().c_str()); } } } diff --git a/Gems/GraphCanvas/Code/Source/Translation/TranslationSerializer.cpp b/Gems/GraphCanvas/Code/Source/Translation/TranslationSerializer.cpp index 80e488f3dc..5f8d8bc3f1 100644 --- a/Gems/GraphCanvas/Code/Source/Translation/TranslationSerializer.cpp +++ b/Gems/GraphCanvas/Code/Source/Translation/TranslationSerializer.cpp @@ -146,7 +146,7 @@ namespace GraphCanvas AZStd::string baseKey = contextStr; if (keyStr.empty()) { - AZ_Error("TranslationDatabase", false, "Every entry in the Translation data must have a key: %s", baseKey.c_str()); + AZ_Warning("TranslationDatabase", false, "Every entry in the Translation data must have a key: %s", baseKey.c_str()); return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported, "Every entry in the Translation data must have a key"); } diff --git a/Gems/ScriptCanvas/Code/Asset/EditorAssetConversionBus.h b/Gems/ScriptCanvas/Code/Asset/EditorAssetConversionBus.h index 12313021f7..3b120af5da 100644 --- a/Gems/ScriptCanvas/Code/Asset/EditorAssetConversionBus.h +++ b/Gems/ScriptCanvas/Code/Asset/EditorAssetConversionBus.h @@ -26,17 +26,14 @@ namespace ScriptCanvas namespace ScriptCanvasEditor { - class ScriptCanvasAsset; - class EditorAssetConversionBusTraits : public AZ::EBusTraits { public: static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; - virtual AZ::Data::Asset LoadAsset(AZStd::string_view graphPath) = 0; - virtual AZ::Outcome CreateLuaAsset(const AZ::Data::Asset& editAsset, AZStd::string_view graphPathForRawLuaFile) = 0; - virtual AZ::Outcome, AZStd::string> CreateRuntimeAsset(const AZ::Data::Asset& editAsset) = 0; + virtual AZ::Outcome CreateLuaAsset(const SourceHandle& editAsset, AZStd::string_view graphPathForRawLuaFile) = 0; + virtual AZ::Outcome, AZStd::string> CreateRuntimeAsset(const SourceHandle& editAsset) = 0; }; using EditorAssetConversionBus = AZ::EBus; diff --git a/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp b/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp index 4df2a57c36..1f614a5a87 100644 --- a/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp +++ b/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp @@ -64,7 +64,6 @@ namespace ScriptCanvasEditor void EditorAssetSystemComponent::Activate() { - m_editorAssetRegistry.Register(); m_editorAssetRegistry.Register(); AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect(); @@ -98,35 +97,25 @@ namespace ScriptCanvasEditor return false; } - AZ::Data::Asset EditorAssetSystemComponent::LoadAsset(AZStd::string_view graphPath) - { - auto outcome = ScriptCanvasBuilder::LoadEditorAsset(graphPath, AZ::Data::AssetId(AZ::Uuid::CreateRandom())); - - if (outcome.IsSuccess()) - { - return outcome.GetValue(); - } - else - { - return {}; - } - } - - AZ::Outcome, AZStd::string> EditorAssetSystemComponent::CreateRuntimeAsset(const AZ::Data::Asset& editAsset) + AZ::Outcome, AZStd::string> EditorAssetSystemComponent::CreateRuntimeAsset(const SourceHandle& editAsset) { return ScriptCanvasBuilder::CreateRuntimeAsset(editAsset); } - AZ::Outcome EditorAssetSystemComponent::CreateLuaAsset(const AZ::Data::Asset& editAsset, AZStd::string_view graphPathForRawLuaFile) + AZ::Outcome EditorAssetSystemComponent::CreateLuaAsset(const SourceHandle& editAsset, AZStd::string_view graphPathForRawLuaFile) { - return ScriptCanvasBuilder::CreateLuaAsset(editAsset->GetScriptCanvasEntity(), editAsset->GetId(), graphPathForRawLuaFile); + return ScriptCanvasBuilder::CreateLuaAsset(editAsset, graphPathForRawLuaFile); } - void EditorAssetSystemComponent::AddSourceFileOpeners([[maybe_unused]] const char* fullSourceFileName, const AZ::Uuid& sourceUuid, AzToolsFramework::AssetBrowser::SourceFileOpenerList& openers) + void EditorAssetSystemComponent::AddSourceFileOpeners + ( [[maybe_unused]] const char* fullSourceFileName + , const AZ::Uuid& sourceUuid + , AzToolsFramework::AssetBrowser::SourceFileOpenerList& openers) { using namespace AzToolsFramework; using namespace AzToolsFramework::AssetBrowser; - if (const SourceAssetBrowserEntry* source = SourceAssetBrowserEntry::GetSourceByUuid(sourceUuid)) // get the full details of the source file based on its UUID. + // get the full details of the source file based on its UUID. + if (const SourceAssetBrowserEntry* source = SourceAssetBrowserEntry::GetSourceByUuid(sourceUuid)) { if (!HandlesSource(source)) { @@ -138,22 +127,31 @@ namespace ScriptCanvasEditor // has no UUID / Not a source file. return; } - // You can push back any number of "Openers" - choose a unique identifier, and icon, and then a lambda which will be activated if the user chooses to open it with your opener: - openers.push_back({ "ScriptCanvas_Editor_Asset_Edit", "Script Canvas Editor...", QIcon(), + + // You can push back any number of "Openers" - choose a unique identifier, and icon, + // and then a lambda which will be activated if the user chooses to open it with your opener: + + openers.push_back({ "ScriptCanvas_Editor_Asset_Edit", "Script Canvas Editor..." + , QIcon(ScriptCanvasAssetDescription().GetIconPathImpl()), [](const char*, const AZ::Uuid& scSourceUuid) - { - AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); - AZ::Data::AssetId sourceAssetId(scSourceUuid, 0); - - auto& assetManager = AZ::Data::AssetManager::Instance(); - AZ::Data::Asset scriptCanvasAsset = assetManager.GetAsset(sourceAssetId, azrtti_typeid(), AZ::Data::AssetLoadBehavior::Default); - AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); - GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, scriptCanvasAsset.GetId(), -1); - if (!openOutcome) { - AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data()); - } - } }); + AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); + if (auto sourceHandle = CompleteDescription(SourceHandle(nullptr, scSourceUuid, {}))) + { + AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); + GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset + , *sourceHandle, Tracker::ScriptCanvasFileState::UNMODIFIED, -1); + if (!openOutcome) + { + AZ_Warning("ScriptCanvas", openOutcome, "%s", openOutcome.GetError().data()); + } + } + else + { + AZ_Warning("ScriptCanvas", false + , "Unabled to find full path for Source UUid %s", scSourceUuid.ToString().c_str()); + } + }}); } } diff --git a/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.h b/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.h index 96e1280cbc..7937950a05 100644 --- a/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.h +++ b/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.h @@ -49,9 +49,8 @@ namespace ScriptCanvasEditor ////////////////////////////////////////////////////////////////////////// // EditorAssetConversionBus::Handler... - AZ::Data::Asset LoadAsset(AZStd::string_view graphPath) override; - AZ::Outcome, AZStd::string> CreateRuntimeAsset(const AZ::Data::Asset& editAsset) override; - AZ::Outcome CreateLuaAsset(const AZ::Data::Asset& editAsset, AZStd::string_view graphPathForRawLuaFile) override; + AZ::Outcome, AZStd::string> CreateRuntimeAsset(const SourceHandle& editAsset) override; + AZ::Outcome CreateLuaAsset(const SourceHandle& editAsset, AZStd::string_view graphPathForRawLuaFile) override; ////////////////////////////////////////////////////////////////////////// ScriptCanvas::AssetRegistry& GetAssetRegistry(); diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp index 0eb748b2f1..00df5ad07b 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp @@ -13,15 +13,50 @@ #include #include #include +#include +#include -namespace ScriptCanvasBuilderCpp +namespace BuildVariableOverridesCpp { - void AppendTabs(AZStd::string& result, size_t depth) + enum Version { - for (size_t i = 0; i < depth; ++i) + Original = 1, + EditorAssetRedux, + + // add description above + Current + }; + + bool VersionConverter + ( AZ::SerializeContext& serializeContext + , AZ::SerializeContext::DataElementNode& rootElement) + { + if (rootElement.GetVersion() < BuildVariableOverridesCpp::Version::EditorAssetRedux) { - result += "\t"; + auto sourceIndex = rootElement.FindElement(AZ_CRC_CE("source")); + if (sourceIndex == -1) + { + AZ_Error("ScriptCanvas", false, "BuildVariableOverrides coversion failed: 'source' was missing"); + return false; + } + + auto& sourceElement = rootElement.GetSubElement(sourceIndex); + AZ::Data::Asset asset; + if (!sourceElement.GetData(asset)) + { + AZ_Error("ScriptCanvas", false, "BuildVariableOverrides coversion failed: could not retrieve 'source' data"); + return false; + } + + ScriptCanvasEditor::SourceHandle sourceHandle(nullptr, asset.GetId().m_guid, {}); + if (!rootElement.AddElementWithData(serializeContext, "source", sourceHandle)) + { + AZ_Error("ScriptCanvas", false, "BuildVariableOverrides coversion failed: could not add updated 'source' data"); + return false; + } } + + return true; } } @@ -29,7 +64,7 @@ namespace ScriptCanvasBuilder { void BuildVariableOverrides::Clear() { - m_source.Reset(); + m_source = {}; m_variables.clear(); m_overrides.clear(); m_overridesUnused.clear(); @@ -39,12 +74,20 @@ namespace ScriptCanvasBuilder void BuildVariableOverrides::CopyPreviousOverriddenValues(const BuildVariableOverrides& source) { - auto copyPreviousIfFound = [](ScriptCanvas::GraphVariable& overriddenValue, const AZStd::vector& source) + auto isEqual = [](const ScriptCanvas::GraphVariable& lhs, const ScriptCanvas::GraphVariable& rhs) { - if (auto iter = AZStd::find_if(source.begin(), source.end(), [&overriddenValue](const auto& candidate) { return candidate.GetVariableId() == overriddenValue.GetVariableId(); }); - iter != source.end()) + return (lhs.GetVariableId() == rhs.GetVariableId() && lhs.GetDataType() == rhs.GetDataType()) + || (lhs.GetVariableName() == rhs.GetVariableName() && lhs.GetDataType() == rhs.GetDataType()); + }; + + auto copyPreviousIfFound = [isEqual](ScriptCanvas::GraphVariable& overriddenValue, const AZStd::vector& source) + { + auto iter = AZStd::find_if(source.begin(), source.end() + , [&overriddenValue, isEqual](const auto& candidate) { return isEqual(candidate, overriddenValue); }); + + if (iter != source.end()) { - overriddenValue.DeepCopy(*iter); + overriddenValue.ModDatum().DeepCopyDatum(*iter->GetDatum()); overriddenValue.SetScriptInputControlVisibility(AZ::Edit::PropertyVisibility::Hide); overriddenValue.SetAllowSignalOnChange(false); return true; @@ -64,6 +107,15 @@ namespace ScriptCanvasBuilder } } + for (auto& overriddenValue : m_overridesUnused) + { + if (!copyPreviousIfFound(overriddenValue, source.m_overridesUnused)) + { + // the variable in question may have been previously used, and is now unused, so copy the previous value over + copyPreviousIfFound(overriddenValue, source.m_overrides); + } + } + ////////////////////////////////////////////////////////////////////////// // #functions2 provide an identifier for the node/variable in the source that caused the dependency. the root will not have one. // the above will provide the data to handle the cases where only certain dependency nodes were removed @@ -100,7 +152,7 @@ namespace ScriptCanvasBuilder if (auto serializeContext = azrtti_cast(reflectContext)) { serializeContext->Class() - ->Version(1) + ->Version(BuildVariableOverridesCpp::Version::Current, &BuildVariableOverridesCpp::VersionConverter) ->Field("source", &BuildVariableOverrides::m_source) ->Field("variables", &BuildVariableOverrides::m_variables) ->Field("entityId", &BuildVariableOverrides::m_entityIds) @@ -194,45 +246,12 @@ namespace ScriptCanvasBuilder } } - EditorAssetTree* EditorAssetTree::ModRoot() - { - if (!m_parent) - { - return this; - } - - return m_parent->ModRoot(); - } - - void EditorAssetTree::SetParent(EditorAssetTree& parent) - { - m_parent = &parent; - } - - AZStd::string EditorAssetTree::ToString(size_t depth) const - { - AZStd::string result; - ScriptCanvasBuilderCpp::AppendTabs(result, depth); - result += m_asset.GetId().ToString(); - result += m_asset.GetHint(); - depth += m_dependencies.empty() ? 0 : 1; - - for (const auto& dependency : m_dependencies) - { - result += "\n"; - ScriptCanvasBuilderCpp::AppendTabs(result, depth); - result += dependency.ToString(depth); - } - - return result; - } - ScriptCanvas::RuntimeDataOverrides ConvertToRuntime(const BuildVariableOverrides& buildOverrides) { ScriptCanvas::RuntimeDataOverrides runtimeOverrides; runtimeOverrides.m_runtimeAsset = AZ::Data::Asset - (AZ::Data::AssetId(buildOverrides.m_source.GetId().m_guid, AZ_CRC("RuntimeData", 0x163310ae)), azrtti_typeid(), {}); + (AZ::Data::AssetId(buildOverrides.m_source.Id(), AZ_CRC("RuntimeData", 0x163310ae)), azrtti_typeid(), {}); runtimeOverrides.m_runtimeAsset.SetAutoLoadBehavior(AZ::Data::AssetLoadBehavior::PreLoad); runtimeOverrides.m_variableIndices.resize(buildOverrides.m_variables.size()); @@ -295,76 +314,9 @@ namespace ScriptCanvasBuilder return runtimeOverrides; } - AZ::Outcome LoadEditorAssetTree(AZ::Data::AssetId editorAssetId, AZStd::string_view assetHint, EditorAssetTree* parent) + AZ::Outcome ParseEditorAssetTree(const ScriptCanvasEditor::EditorAssetTree& editorAssetTree) { - EditorAssetTree result; - AZ::Data::AssetInfo assetInfo; - AZStd::string watchFolder; - bool resultFound = false; - - if (!AzToolsFramework::AssetSystemRequestBus::FindFirstHandler()) - { - return AZ::Failure(AZStd::string("LoadEditorAssetTree found no handler for AzToolsFramework::AssetSystemRequestBus.")); - } - - AzToolsFramework::AssetSystemRequestBus::BroadcastResult - ( resultFound - , &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourceUUID - , editorAssetId.m_guid - , assetInfo - , watchFolder); - - if (!resultFound) - { - return AZ::Failure(AZStd::string::format("LoadEditorAssetTree failed to get engine relative path from %s-%.*s.", editorAssetId.ToString().c_str(), aznumeric_cast(assetHint.size()), assetHint.data())); - } - - AZStd::vector dependentAssets; - - auto filterCB = [&dependentAssets](const AZ::Data::AssetFilterInfo& filterInfo)->bool - { - if (filterInfo.m_assetType == azrtti_typeid()) - { - dependentAssets.push_back(AZ::Data::AssetId(filterInfo.m_assetId.m_guid, 0)); - } - else if (filterInfo.m_assetType == azrtti_typeid()) - { - dependentAssets.push_back(filterInfo.m_assetId); - } - - return true; - }; - - auto loadAssetOutcome = ScriptCanvasBuilder::LoadEditorAsset(assetInfo.m_relativePath, editorAssetId, filterCB); - if (!loadAssetOutcome.IsSuccess()) - { - return AZ::Failure(AZStd::string::format("LoadEditorAssetTree failed to load graph from %s-%s: %s", editorAssetId.ToString().c_str(), assetHint.data(), loadAssetOutcome.GetError().c_str())); - } - - for (auto& dependentAsset : dependentAssets) - { - auto loadDependentOutcome = LoadEditorAssetTree(dependentAsset, "", &result); - if (!loadDependentOutcome.IsSuccess()) - { - return AZ::Failure(AZStd::string::format("LoadEditorAssetTree failed to load dependent graph from %s-%s: %s", editorAssetId.ToString().c_str(), assetHint.data(), loadDependentOutcome.GetError().c_str())); - } - - result.m_dependencies.push_back(loadDependentOutcome.TakeValue()); - } - - if (parent) - { - result.SetParent(*parent); - } - - result.m_asset = loadAssetOutcome.TakeValue(); - - return AZ::Success(result); - } - - AZ::Outcome ParseEditorAssetTree(const EditorAssetTree& editorAssetTree) - { - auto buildEntity = editorAssetTree.m_asset->GetScriptCanvasEntity(); + auto buildEntity = editorAssetTree.m_asset.Get()->GetEntity(); if (!buildEntity) { return AZ::Failure(AZStd::string("No entity from source asset")); @@ -400,9 +352,8 @@ namespace ScriptCanvasBuilder if (!parseDependentOutcome.IsSuccess()) { return AZ::Failure(AZStd::string::format - ( "ParseEditorAssetTree failed to parse dependent graph from %s-%s: %s" - , dependentAsset.m_asset.GetId().ToString().c_str() - , dependentAsset.m_asset.GetHint().c_str() + ( "ParseEditorAssetTree failed to parse dependent graph from %s: %s" + , dependentAsset.m_asset.ToString().c_str() , parseDependentOutcome.GetError().c_str())); } diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.h b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.h index f03e78bc3e..5cffa823dc 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.h +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.h @@ -16,6 +16,7 @@ namespace ScriptCanvasEditor { class ScriptCanvasAsset; + class EditorAssetTree; } namespace ScriptCanvasBuilder @@ -39,8 +40,8 @@ namespace ScriptCanvasBuilder void PopulateFromParsedResults(ScriptCanvas::Grammar::AbstractCodeModelConstPtr abstractCodeModel, const ScriptCanvas::VariableData& variables); // #functions2 provide an identifier for the node/variable in the source that caused the dependency. the root will not have one. - AZ::Data::Asset m_source; - + ScriptCanvasEditor::SourceHandle m_source; + // all of the variables here are overrides AZStd::vector m_variables; // the values here may or may not be overrides @@ -48,30 +49,11 @@ namespace ScriptCanvasBuilder // these two variable lists are all that gets exposed to the edit context AZStd::vector m_overrides; AZStd::vector m_overridesUnused; - // AZStd::vector m_entityIdRuntimeInputIndices; since all of the entity ids need to go in, they may not need indices AZStd::vector m_dependencies; }; - class EditorAssetTree - { - public: - AZ_CLASS_ALLOCATOR(EditorAssetTree, AZ::SystemAllocator, 0); - - EditorAssetTree* m_parent = nullptr; - AZStd::vector m_dependencies; - AZ::Data::Asset m_asset; - - EditorAssetTree* ModRoot(); - - void SetParent(EditorAssetTree& parent); - - AZStd::string ToString(size_t depth = 0) const; - }; - // copy the variables overridden during editor / prefab build time back to runtime data ScriptCanvas::RuntimeDataOverrides ConvertToRuntime(const BuildVariableOverrides& overrides); - AZ::Outcome LoadEditorAssetTree(AZ::Data::AssetId editorAssetId, AZStd::string_view assetHint, EditorAssetTree* parent = nullptr); - - AZ::Outcome ParseEditorAssetTree(const EditorAssetTree& editorAssetTree); + AZ::Outcome ParseEditorAssetTree(const ScriptCanvasEditor::EditorAssetTree& editorAssetTree); } diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.cpp index a37fa47b62..019dd4f5e3 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.cpp @@ -48,7 +48,6 @@ namespace ScriptCanvasBuilder SharedHandlers HandleAssetTypes() { SharedHandlers handlers; - handlers.m_editorAssetHandler = RegisterHandler("scriptcanvas", false); handlers.m_subgraphInterfaceHandler = RegisterHandler("scriptcanvas_fn_compiled", true); handlers.m_runtimeAssetHandler = RegisterHandler("scriptcanvas_compiled", true); diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp index f474c10532..6c35007987 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -27,12 +28,12 @@ #include #include #include +#include namespace ScriptCanvasBuilder { void Worker::Activate(const AssetHandlers& handlers) { - m_editorAssetHandler = handlers.m_editorAssetHandler; m_runtimeAssetHandler = handlers.m_runtimeAssetHandler; m_subgraphInterfaceHandler = handlers.m_subgraphInterfaceHandler; } @@ -44,54 +45,22 @@ namespace ScriptCanvasBuilder AzFramework::StringFunc::Path::ConstructFull(request.m_watchFolder.data(), request.m_sourceFile.data(), fullPath, false); AzFramework::StringFunc::Path::Normalize(fullPath); - if (!m_editorAssetHandler) - { - AZ_Error(s_scriptCanvasBuilder, false, R"(CreateJobs for %s failed because the ScriptCanvas Editor Asset handler is missing.)", fullPath.data()); - } - - AZStd::shared_ptr assetDataStream = AZStd::make_shared(); - - AZ::IO::FileIOStream stream(fullPath.c_str(), AZ::IO::OpenMode::ModeRead); - if (!AZ::IO::RetryOpenStream(stream)) - { - AZ_Warning(s_scriptCanvasBuilder, false, "CreateJobs for \"%s\" failed because the source file could not be opened.", fullPath.data()); - return; - } - - // Read the asset into a memory buffer, then hand ownership of the buffer to assetDataStream - { - AZ::IO::FileIOStream ioStream; - if (!ioStream.Open(fullPath.data(), AZ::IO::OpenMode::ModeRead)) - { - AZ_Warning(s_scriptCanvasBuilder, false, "CreateJobs for \"%s\" failed because the source file could not be opened.", fullPath.data()); - return; - } - - AZStd::vector fileBuffer(ioStream.GetLength()); - size_t bytesRead = ioStream.Read(fileBuffer.size(), fileBuffer.data()); - if (bytesRead != ioStream.GetLength()) - { - AZ_Warning(s_scriptCanvasBuilder, false, AZStd::string::format("File failed to read completely: %s", fullPath.data()).c_str()); - return; - } - - assetDataStream->Open(AZStd::move(fileBuffer)); - } - - m_processEditorAssetDependencies.clear(); - AZ::Data::Asset asset; - asset.Create(AZ::Data::AssetId(AZ::Uuid::CreateRandom())); - if (m_editorAssetHandler->LoadAssetDataFromStream(asset, assetDataStream, {}) != AZ::Data::AssetHandler::LoadResult::LoadComplete) - { - AZ_Warning(s_scriptCanvasBuilder, false, "CreateJobs for \"%s\" failed because the asset data could not be loaded from the file", fullPath.data()); - return; - } + const ScriptCanvasEditor::Graph* sourceGraph = nullptr; + const ScriptCanvas::GraphData* graphData = nullptr; - auto* scriptCanvasEntity = asset.Get()->GetScriptCanvasEntity(); - auto* sourceGraph = AZ::EntityUtils::FindFirstDerivedComponent(scriptCanvasEntity); + ScriptCanvasEditor::SourceHandle sourceHandle; + + auto sourceOutcome = ScriptCanvasEditor::LoadFromFile(fullPath); + if (sourceOutcome.IsSuccess()) + { + sourceHandle = sourceOutcome.TakeValue(); + sourceGraph = sourceHandle.Get(); + graphData = sourceGraph->GetGraphDataConst(); + } + AZ_Assert(sourceGraph, "Graph component is missing from entity."); - AZ_Assert(sourceGraph->GetGraphData(), "GraphData is missing from entity"); + AZ_Assert(graphData, "GraphData is missing from entity"); struct EntityIdComparer { @@ -102,7 +71,7 @@ namespace ScriptCanvasBuilder return lhsEntityId < rhsEntityId; } }; - const AZStd::set sortedEntities(sourceGraph->GetGraphData()->m_nodes.begin(), sourceGraph->GetGraphData()->m_nodes.end()); + const AZStd::set sortedEntities(graphData->m_nodes.begin(), graphData->m_nodes.end()); size_t fingerprint = 0; for (const auto& nodeEntity : sortedEntities) @@ -155,7 +124,7 @@ namespace ScriptCanvasBuilder }; AZ_Verify(serializeContext->EnumerateInstanceConst - ( sourceGraph->GetGraphData() + ( graphData , azrtti_typeid() , assetFilter , {} @@ -168,17 +137,6 @@ namespace ScriptCanvasBuilder for (const AssetBuilderSDK::PlatformInfo& info : request.m_enabledPlatforms) { - if (info.HasTag("tools")) - { - AssetBuilderSDK::JobDescriptor copyDescriptor; - copyDescriptor.m_priority = 2; - copyDescriptor.m_critical = true; - copyDescriptor.m_jobKey = s_scriptCanvasCopyJobKey; - copyDescriptor.SetPlatformIdentifier(info.m_identifier.c_str()); - copyDescriptor.m_additionalFingerprintInfo = AZStd::string(GetFingerprintString()).append("|").append(AZStd::to_string(static_cast(fingerprint))); - response.m_createJobOutputs.push_back(copyDescriptor); - } - AssetBuilderSDK::JobDescriptor jobDescriptor; jobDescriptor.m_priority = 2; jobDescriptor.m_critical = true; @@ -244,49 +202,14 @@ namespace ScriptCanvasBuilder return; } - if (!m_editorAssetHandler) - { - AZ_Error(s_scriptCanvasBuilder, false, R"(Exporting of .scriptcanvas for "%s" file failed as no editor asset handler was registered for script canvas. The ScriptCanvas Gem might not be enabled.)", fullPath.data()); - return; - } - if (!m_runtimeAssetHandler) { AZ_Error(s_scriptCanvasBuilder, false, R"(Exporting of .scriptcanvas for "%s" file failed as no runtime asset handler was registered for script canvas.)", fullPath.data()); return; } - AZStd::shared_ptr assetDataStream = AZStd::make_shared(); - - AZ::IO::FileIOStream stream(fullPath.c_str(), AZ::IO::OpenMode::ModeRead); - if (!AZ::IO::RetryOpenStream(stream)) - { - AZ_Warning(s_scriptCanvasBuilder, false, "CreateJobs for \"%s\" failed because the source file could not be opened.", fullPath.data()); - return; - } - - // Read the asset into a memory buffer, then hand ownership of the buffer to assetDataStream - { - AZ::IO::FileIOStream ioStream; - if (!ioStream.Open(fullPath.data(), AZ::IO::OpenMode::ModeRead)) - { - AZ_Warning(s_scriptCanvasBuilder, false, "CreateJobs for \"%s\" failed because the source file could not be opened.", fullPath.data()); - return; - } - AZStd::vector fileBuffer(ioStream.GetLength()); - size_t bytesRead = ioStream.Read(fileBuffer.size(), fileBuffer.data()); - if (bytesRead != ioStream.GetLength()) - { - AZ_Warning(s_scriptCanvasBuilder, false, AZStd::string::format("File failed to read completely: %s", fullPath.data()).c_str()); - return; - } - - assetDataStream->Open(AZStd::move(fileBuffer)); - } - - AZ::Data::Asset asset; - asset.Create(request.m_sourceFileUUID); - if (m_editorAssetHandler->LoadAssetDataFromStream(asset, assetDataStream, nullptr) != AZ::Data::AssetHandler::LoadResult::LoadComplete) + auto loadOutcome = ScriptCanvasEditor::LoadFromFile(request.m_fullPath); + if (!loadOutcome.IsSuccess()) { AZ_Error(s_scriptCanvasBuilder, false, R"(Loading of ScriptCanvas asset for source file "%s" has failed)", fullPath.data()); return; @@ -299,23 +222,11 @@ namespace ScriptCanvasBuilder AzFramework::StringFunc::Path::Join(request.m_tempDirPath.c_str(), fileNameOnly.c_str(), runtimeScriptCanvasOutputPath, true, true); AzFramework::StringFunc::Path::ReplaceExtension(runtimeScriptCanvasOutputPath, ScriptCanvas::RuntimeAsset::GetFileExtension()); - if (request.m_jobDescription.m_jobKey == s_scriptCanvasCopyJobKey) - { - // ScriptCanvas Editor Asset Copy job - // The SubID is zero as this represents the main asset - AssetBuilderSDK::JobProduct jobProduct; - jobProduct.m_productFileName = fullPath; - jobProduct.m_productAssetType = azrtti_typeid(); - jobProduct.m_productSubID = 0; - jobProduct.m_dependenciesHandled = true; - jobProduct.m_dependencies.clear(); - response.m_outputProducts.push_back(AZStd::move(jobProduct)); - response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success; - } - else - { - AZ::Entity* buildEntity = asset.Get()->GetScriptCanvasEntity(); + auto sourceHandle = loadOutcome.TakeValue(); + if (request.m_jobDescription.m_jobKey == s_scriptCanvasProcessJobKey) + { + AZ::Entity* buildEntity = sourceHandle.Get()->GetEntity(); ProcessTranslationJobInput input; input.assetID = AZ::Data::AssetId(request.m_sourceFileUUID, AZ_CRC("RuntimeData", 0x163310ae)); input.request = &request; @@ -370,7 +281,8 @@ namespace ScriptCanvasBuilder } else { - if (AzFramework::StringFunc::Find(fileNameOnly, s_unitTestParseErrorPrefix) != AZStd::string::npos) + if (!ScriptCanvas::Grammar::g_processingErrorsForUnitTestsEnabled + && AzFramework::StringFunc::Find(fileNameOnly, s_unitTestParseErrorPrefix) != AZStd::string::npos) { response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success; } diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h index 668e1a0bcd..817fe5d294 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h @@ -37,12 +37,12 @@ namespace ScriptCanvasEditor { class Graph; class ScriptCanvasAsset; + class SourceHandle; } namespace ScriptCanvasBuilder { constexpr const char* s_scriptCanvasBuilder = "ScriptCanvasBuilder"; - constexpr const char* s_scriptCanvasCopyJobKey = "Script Canvas Copy Job"; constexpr const char* s_scriptCanvasProcessJobKey = "Script Canvas Process Job"; constexpr const char* s_unitTestParseErrorPrefix = "LY_SC_UnitTest"; @@ -59,6 +59,8 @@ namespace ScriptCanvasBuilder PrefabIntegration, CorrectGraphVariableVersion, ReflectEntityIdNodes, + FixExecutionStateNodeableConstruction, + // add new entries above Current, }; @@ -69,7 +71,6 @@ namespace ScriptCanvasBuilder struct AssetHandlers { - AZ::Data::AssetHandler* m_editorAssetHandler = nullptr; AZ::Data::AssetHandler* m_editorFunctionAssetHandler = nullptr; AZ::Data::AssetHandler* m_runtimeAssetHandler = nullptr; AZ::Data::AssetHandler* m_subgraphInterfaceHandler = nullptr; @@ -80,7 +81,6 @@ namespace ScriptCanvasBuilder struct SharedHandlers { - HandlerOwnership m_editorAssetHandler{}; HandlerOwnership m_editorFunctionAssetHandler{}; HandlerOwnership m_runtimeAssetHandler{}; HandlerOwnership m_subgraphInterfaceHandler{}; @@ -122,13 +122,13 @@ namespace ScriptCanvasBuilder } }; - AZ::Outcome, AZStd::string> CreateRuntimeAsset(const AZ::Data::Asset& asset); + AZ::Outcome, AZStd::string> CreateRuntimeAsset(const ScriptCanvasEditor::SourceHandle& asset); AZ::Outcome CompileGraphData(AZ::Entity* scriptCanvasEntity); AZ::Outcome CompileVariableData(AZ::Entity* scriptCanvasEntity); - AZ::Outcome CreateLuaAsset(AZ::Entity* buildEntity, AZ::Data::AssetId scriptAssetId, AZStd::string_view rawLuaFilePath); + AZ::Outcome CreateLuaAsset(const ScriptCanvasEditor::SourceHandle& editAsset, AZStd::string_view rawLuaFilePath); int GetBuilderVersion(); @@ -169,7 +169,6 @@ namespace ScriptCanvasBuilder void ShutDown() override {}; private: - AZ::Data::AssetHandler* m_editorAssetHandler = nullptr; AZ::Data::AssetHandler* m_runtimeAssetHandler = nullptr; AZ::Data::AssetHandler* m_subgraphInterfaceHandler = nullptr; diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp index 7d4cfec909..fb7b5e7a4a 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp @@ -29,19 +29,20 @@ #include #include #include +#include +#include + namespace ScriptCanvasBuilder { AssetHandlers::AssetHandlers(SharedHandlers& source) - : m_editorAssetHandler(source.m_editorAssetHandler.first) - , m_editorFunctionAssetHandler(source.m_editorFunctionAssetHandler.first) + : m_editorFunctionAssetHandler(source.m_editorFunctionAssetHandler.first) , m_runtimeAssetHandler(source.m_runtimeAssetHandler.first) , m_subgraphInterfaceHandler(source.m_subgraphInterfaceHandler.first) {} void SharedHandlers::DeleteOwnedHandlers() { - DeleteIfOwned(m_editorAssetHandler); DeleteIfOwned(m_editorFunctionAssetHandler); DeleteIfOwned(m_runtimeAssetHandler); DeleteIfOwned(m_subgraphInterfaceHandler); @@ -77,36 +78,23 @@ namespace ScriptCanvasBuilder return ScriptCanvas::Translation::ParseGraph(request); } - AZ::Outcome CreateLuaAsset(AZ::Entity* buildEntity, AZ::Data::AssetId scriptAssetId, AZStd::string_view rawLuaFilePath) + AZ::Outcome CreateLuaAsset(const ScriptCanvasEditor::SourceHandle& editAsset, AZStd::string_view rawLuaFilePath) { AZStd::string fullPath(rawLuaFilePath); AZStd::string fileNameOnly; AzFramework::StringFunc::Path::GetFullFileName(rawLuaFilePath.data(), fileNameOnly); AzFramework::StringFunc::Path::Normalize(fullPath); - auto sourceGraph = PrepareSourceGraph(buildEntity); + auto sourceGraph = PrepareSourceGraph(editAsset.Mod()->GetEntity()); ScriptCanvas::Grammar::Request request; - request.scriptAssetId = scriptAssetId; + request.scriptAssetId = editAsset.Id(); request.graph = sourceGraph; request.name = fileNameOnly; request.rawSaveDebugOutput = ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile; request.printModelToConsole = ScriptCanvas::Grammar::g_printAbstractCodeModel; request.path = fullPath; - bool pathFound = false; - AZStd::string relativePath; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult - ( pathFound - , &AzToolsFramework::AssetSystem::AssetSystemRequest::GetRelativeProductPathFromFullSourceOrProductPath - , fullPath.c_str(), relativePath); - - if (!pathFound) - { - AZ::Failure(AZStd::string::format("Failed to get engine relative path from %s", fullPath.c_str())); - } - - request.namespacePath = relativePath; const ScriptCanvas::Translation::Result translationResult = TranslateToLua(request); auto isSuccessOutcome = translationResult.IsSuccess(ScriptCanvas::Translation::TargetFlags::Lua); @@ -117,7 +105,7 @@ namespace ScriptCanvasBuilder auto& translation = translationResult.m_translations.find(ScriptCanvas::Translation::TargetFlags::Lua)->second; AZ::Data::Asset asset; - scriptAssetId.m_subId = AZ::ScriptAsset::CompiledAssetSubId; + AZ::Data::AssetId scriptAssetId(editAsset.Id(), AZ::ScriptAsset::CompiledAssetSubId); asset.Create(scriptAssetId); auto writeStream = asset.Get()->CreateWriteStream(); @@ -144,12 +132,12 @@ namespace ScriptCanvasBuilder return AZ::Success(result); } - AZ::Outcome, AZStd::string> CreateRuntimeAsset(const AZ::Data::Asset& editAsset) + AZ::Outcome, AZStd::string> CreateRuntimeAsset(const ScriptCanvasEditor::SourceHandle& editAsset) { // Flush asset manager events to ensure no asset references are held by closures queued on Ebuses. AZ::Data::AssetManager::Instance().DispatchEvents(); - auto runtimeAssetId = editAsset.GetId(); + AZ::Data::AssetId runtimeAssetId = editAsset.Id(); runtimeAssetId.m_subId = AZ_CRC("RuntimeData", 0x163310ae); AZ::Data::Asset runtimeAsset; runtimeAsset.Create(runtimeAssetId); diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHandler.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHandler.cpp index dea63ab852..896d285054 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHandler.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHandler.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -93,49 +94,6 @@ namespace ScriptCanvasEditor } } - AZ::Outcome LoadScriptCanvasDataFromJson - ( ScriptCanvas::ScriptCanvasData& dataTarget - , AZStd::string_view source - , AZ::SerializeContext& serializeContext) - { - namespace JSRU = AZ::JsonSerializationUtils; - using namespace ScriptCanvas; - - AZ::JsonDeserializerSettings settings; - settings.m_serializeContext = &serializeContext; - settings.m_metadata.Create(); - - auto loadResult = JSRU::LoadObjectFromStringByType - ( &dataTarget - , azrtti_typeid() - , source - , &settings); - - if (!loadResult.IsSuccess()) - { - return loadResult; - } - - if (auto graphData = dataTarget.ModGraph()) - { - auto listeners = settings.m_metadata.Find(); - AZ_Assert(listeners, "Failed to find SerializationListeners"); - - ScriptCanvasAssetHandlerCpp::CollectNodes(graphData->GetGraphData()->m_nodes, *listeners); - - for (auto listener : *listeners) - { - listener->OnDeserialize(); - } - } - else - { - return AZ::Failure(AZStd::string("Failed to find graph data after loading source")); - } - - return AZ::Success(); - } - AZ::Data::AssetHandler::LoadResult ScriptCanvasAssetHandler::LoadAssetData ( const AZ::Data::Asset& assetTarget , AZStd::shared_ptr streamSource @@ -167,7 +125,7 @@ namespace ScriptCanvasEditor settings.m_serializeContext = m_serializeContext; settings.m_metadata.Create(); // attempt JSON deserialization... - auto jsonResult = LoadScriptCanvasDataFromJson + auto jsonResult = LoadDataFromJson ( scriptCanvasDataTarget , AZStd::string_view{ byteBuffer.begin(), byteBuffer.size() } , *m_serializeContext); @@ -228,6 +186,7 @@ namespace ScriptCanvasEditor , AZ::IO::GenericStream* stream , [[maybe_unused]] AZ::DataStream::StreamType streamType) { + // #sc_editor_asset delete usage of this, and route to ScriptCanvasEditor::SaveToStream namespace JSRU = AZ::JsonSerializationUtils; using namespace ScriptCanvas; diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHolder.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHolder.cpp index a42a9bad48..f8c89ae7e5 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHolder.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHolder.cpp @@ -82,30 +82,6 @@ namespace ScriptCanvasEditor void ScriptCanvasAssetHolder::OpenEditor() const { - AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); - - AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); - - if (m_scriptCanvasAsset.IsReady()) - { - GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, m_scriptCanvasAsset.GetId(), -1); - - if (!openOutcome) - { - AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data()); - } - } - else if (m_ownerId.first.IsValid()) - { - AzToolsFramework::EntityIdList selectedEntityIds; - AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(selectedEntityIds, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities); - - // Going to bypass the multiple selected entities flow for right now. - if (selectedEntityIds.size() == 1) - { - GeneralRequestBus::Broadcast(&GeneralRequests::CreateScriptCanvasAssetFor, m_ownerId); - } - } } ScriptCanvas::ScriptCanvasId ScriptCanvasAssetHolder::GetScriptCanvasId() const diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.cpp index b24e91889e..09b967281d 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.cpp @@ -58,111 +58,8 @@ namespace ScriptCanvasEditor SaveAs(assetId, {}, onSaveCallback); } - void AssetTracker::SaveAs(AZ::Data::AssetId assetId, const AZStd::string& path, Callbacks::OnSave onSaveCallback) + void AssetTracker::SaveAs(AZ::Data::AssetId /*assetId*/, const AZStd::string& /*path*/, Callbacks::OnSave /*onSaveCallback*/) { - auto assetIter = m_assetsInUse.find(assetId); - - if (assetIter != m_assetsInUse.end()) - { - auto onSave = [this, assetId, onSaveCallback](bool saveSuccess, AZ::Data::AssetPtr asset, AZ::Data::AssetId previousFileAssetId) - { - AZ::Data::AssetId signalId = assetId; - AZ::Data::AssetId fileAssetId = asset->GetId(); - - // If there is a previous file Id is valid, it means this is a save-as operation and we need to remap the tracking. - if (previousFileAssetId.IsValid()) - { - if (saveSuccess) - { - fileAssetId = m_assetsInUse[assetId]->GetFileAssetId(); - m_remappedAsset[asset->GetId()] = fileAssetId; - - // Erase the asset first so the smart pointer can deal with it's things. - m_assetsInUse.erase(fileAssetId); - - // Then perform the insert once we know nothing will attempt to delete this while we are operating on it. - m_assetsInUse[fileAssetId] = m_assetsInUse[assetId]; - m_assetsInUse.erase(assetId); - } - - m_savingAssets.erase(assetId); - m_savingAssets.insert(fileAssetId); - - signalId = fileAssetId; - - if (m_queuedCloses.erase(assetId)) - { - m_queuedCloses.insert(fileAssetId); - } - - auto assetIter = m_assetsInUse.find(fileAssetId); - - if (assetIter != m_assetsInUse.end()) - { - AZStd::invoke(onSaveCallback, saveSuccess, m_assetsInUse[fileAssetId]->GetAsset().Get(), previousFileAssetId); - } - else - { - AZ_Error("ScriptCanvas", !saveSuccess, "Unable to find Memory Asset for Asset(%s)", fileAssetId.ToString().c_str()); - AZStd::invoke(onSaveCallback, saveSuccess, asset, previousFileAssetId); - } - } - else - { - if (saveSuccess) - { - // This should be the case when we get a save as from a newly created file. - // - // If we find the 'memory' asset id in the assets in use. This means this was a new file that was saved. - // To maintain all of the look-up stuff, we need to treat this like a remapping stage. - auto assetInUseIter = m_assetsInUse.find(assetId); - if (assetInUseIter != m_assetsInUse.end()) - { - fileAssetId = assetInUseIter->second->GetFileAssetId(); - - if (assetId != fileAssetId) - { - m_remappedAsset[assetId] = fileAssetId; - - m_assetsInUse.erase(fileAssetId); - m_assetsInUse[fileAssetId] = AZStd::move(assetInUseIter->second); - m_assetsInUse.erase(assetId); - - m_savingAssets.erase(assetId); - m_savingAssets.insert(fileAssetId); - - if (m_queuedCloses.erase(assetId)) - { - m_queuedCloses.insert(fileAssetId); - } - } - } - else - { - fileAssetId = CheckAssetId(fileAssetId); - } - - signalId = fileAssetId; - } - - if (onSaveCallback) - { - AZStd::invoke(onSaveCallback, saveSuccess, m_assetsInUse[signalId]->GetAsset().Get(), previousFileAssetId); - } - - AssetTrackerNotificationBus::Broadcast(&AssetTrackerNotifications::OnAssetSaved, m_assetsInUse[signalId], saveSuccess); - } - - SignalSaveComplete(signalId); - }; - - m_savingAssets.insert(assetId); - assetIter->second->SaveAs(path, onSave); - } - else - { - AZ_Assert(false, "Cannot SaveAs into an existing AssetId"); - } } bool AssetTracker::Load(AZ::Data::AssetId fileAssetId, AZ::Data::AssetType assetType, Callbacks::OnAssetReadyCallback onAssetReadyCallback) @@ -541,48 +438,4 @@ namespace ScriptCanvasEditor return AZ::EntityId(); } - void AssetTracker::OnAssetReady(const ScriptCanvasMemoryAsset* asset) - { - AZ::Data::AssetId assetId = CheckAssetId(asset->GetId()); - - auto assetInUseIter = m_assetsInUse.find(assetId); - if (assetInUseIter != m_assetsInUse.end()) - { - AssetTrackerNotificationBus::Broadcast(&AssetTrackerNotifications::OnAssetReady, assetInUseIter->second); - } - } - - void AssetTracker::OnAssetReloaded(const ScriptCanvasMemoryAsset* asset) - { - AZ::Data::AssetId assetId = CheckAssetId(asset->GetId()); - - auto assetInUseIter = m_assetsInUse.find(assetId); - if (assetInUseIter != m_assetsInUse.end()) - { - AssetTrackerNotificationBus::Broadcast(&AssetTrackerNotifications::OnAssetReloaded, assetInUseIter->second); - } - } - - void AssetTracker::OnAssetSaved(const ScriptCanvasMemoryAsset* asset, bool isSuccessful) - { - AZ::Data::AssetId assetId = CheckAssetId(asset->GetId()); - - auto assetInUseIter = m_assetsInUse.find(assetId); - if (assetInUseIter != m_assetsInUse.end()) - { - AssetTrackerNotificationBus::Broadcast(&AssetTrackerNotifications::OnAssetSaved, assetInUseIter->second, isSuccessful); - } - } - - void AssetTracker::OnAssetError(const ScriptCanvasMemoryAsset* asset) - { - AZ::Data::AssetId assetId = CheckAssetId(asset->GetId()); - - auto assetInUseIter = m_assetsInUse.find(assetId); - if (assetInUseIter != m_assetsInUse.end()) - { - AssetTrackerNotificationBus::Broadcast(&AssetTrackerNotifications::OnAssetError, assetInUseIter->second); - } - } - } diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.h b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.h index 78e85651e1..aa06029c98 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.h +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.h @@ -16,6 +16,7 @@ #include #include +#include namespace ScriptCanvasEditor @@ -119,10 +120,5 @@ namespace ScriptCanvasEditor // Invoked when an asset is loaded from file and becomes ready Callbacks::OnAssetReadyCallback m_onAssetReadyCallback; - // Internal::MemoryAssetNotificationBus - void OnAssetReady(const ScriptCanvasMemoryAsset* asset) override; - void OnAssetReloaded(const ScriptCanvasMemoryAsset* asset) override; - void OnAssetSaved(const ScriptCanvasMemoryAsset* asset, bool isSuccessful) override; - void OnAssetError(const ScriptCanvasMemoryAsset* asset) override; }; } diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerBus.h b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerBus.h index 3fecb0aac9..7125cb7d9b 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerBus.h +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerBus.h @@ -17,6 +17,7 @@ #include #include +#include class QWidget; @@ -154,17 +155,5 @@ namespace ScriptCanvasEditor using MemoryAssetSystemNotificationBus = AZ::EBus; } - class MemoryAssetNotifications - : public AZ::EBusTraits - { - public: - static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; - static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; - using BusIdType = AZ::Data::AssetId; - - virtual void OnFileStateChanged(Tracker::ScriptCanvasFileState) {} - }; - - using MemoryAssetNotificationBus = AZ::EBus; ////////////////////////////////////////////////////////////////////////////////////////////////////////// } diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerDefinitions.h b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerDefinitions.h index e08ce8b74b..73507112c2 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerDefinitions.h +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerDefinitions.h @@ -18,22 +18,11 @@ namespace ScriptCanvasEditor namespace Callbacks { //! Callback used to know when a save operation failed or succeeded - using OnSave = AZStd::function; + using OnSave = AZStd::function; using OnAssetReadyCallback = AZStd::function; using OnAssetCreatedCallback = OnAssetReadyCallback; } - namespace Tracker - { - enum class ScriptCanvasFileState : AZ::s32 - { - NEW, - MODIFIED, - UNMODIFIED, - SOURCE_REMOVED, - INVALID = -1 - }; - } } diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp new file mode 100644 index 0000000000..c4579c9042 --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp @@ -0,0 +1,329 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ScriptCanvasFileHandlingCpp +{ + void AppendTabs(AZStd::string& result, size_t depth) + { + for (size_t i = 0; i < depth; ++i) + { + result += "\t"; + } + } + + void CollectNodes(const ScriptCanvas::GraphData::NodeContainer& container, ScriptCanvas::SerializationListeners& listeners) + { + for (auto& nodeEntity : container) + { + if (nodeEntity) + { + if (auto listener = azrtti_cast + ( AZ::EntityUtils::FindFirstDerivedComponent(nodeEntity))) + { + listeners.push_back(listener); + } + } + } + } +} + +namespace ScriptCanvasEditor +{ + EditorAssetTree* EditorAssetTree::ModRoot() + { + if (!m_parent) + { + return this; + } + + return m_parent->ModRoot(); + } + + void EditorAssetTree::SetParent(EditorAssetTree& parent) + { + m_parent = &parent; + } + + AZStd::string EditorAssetTree::ToString(size_t depth) const + { + AZStd::string result; + ScriptCanvasFileHandlingCpp::AppendTabs(result, depth); + result += m_asset.ToString(); + depth += m_dependencies.empty() ? 0 : 1; + + for (const auto& dependency : m_dependencies) + { + result += "\n"; + ScriptCanvasFileHandlingCpp::AppendTabs(result, depth); + result += dependency.ToString(depth); + } + + return result; + } + + AZ::Outcome LoadDataFromJson + ( ScriptCanvas::ScriptCanvasData& dataTarget + , AZStd::string_view source + , AZ::SerializeContext& serializeContext) + { + namespace JSRU = AZ::JsonSerializationUtils; + using namespace ScriptCanvas; + + AZ::JsonDeserializerSettings settings; + settings.m_serializeContext = &serializeContext; + settings.m_metadata.Create(); + + auto loadResult = JSRU::LoadObjectFromStringByType + ( &dataTarget + , azrtti_typeid() + , source + , &settings); + + if (!loadResult.IsSuccess()) + { + return loadResult; + } + + if (auto graphData = dataTarget.ModGraph()) + { + auto listeners = settings.m_metadata.Find(); + AZ_Assert(listeners, "Failed to find SerializationListeners"); + + ScriptCanvasFileHandlingCpp::CollectNodes(graphData->GetGraphData()->m_nodes, *listeners); + + for (auto listener : *listeners) + { + listener->OnDeserialize(); + } + } + else + { + return AZ::Failure(AZStd::string("Failed to find graph data after loading source")); + } + + return AZ::Success(); + } + + + AZ::Outcome LoadEditorAssetTree(SourceHandle handle, EditorAssetTree* parent) + { + if (!CompleteDescriptionInPlace(handle)) + { + return AZ::Failure(AZStd::string::format("LoadEditorAssetTree failed to describe graph from %s", handle.ToString().c_str())); + } + + if (!handle.Get()) + { + auto loadAssetOutcome = LoadFromFile(handle.Path().c_str()); + if (!loadAssetOutcome.IsSuccess()) + { + return AZ::Failure(AZStd::string::format("LoadEditorAssetTree failed to load graph from %s: %s" + , handle.ToString().c_str(), loadAssetOutcome.GetError().c_str())); + } + + handle = SourceHandle(loadAssetOutcome.GetValue(), handle.Id(), handle.Path().c_str()); + } + + AZStd::vector dependentAssets; + const auto subgraphInterfaceAssetTypeID = azrtti_typeid>(); + + auto beginElementCB = [&subgraphInterfaceAssetTypeID, &dependentAssets] + ( void* instance + , const AZ::SerializeContext::ClassData* classData + , const AZ::SerializeContext::ClassElement* classElement) -> bool + { + if (classElement) + { + // if we are a pointer, then we may be pointing to a derived type. + if (classElement->m_flags & AZ::SerializeContext::ClassElement::FLG_POINTER) + { + // if ptr is a pointer-to-pointer, cast its value to a void* (or const void*) and dereference to get to the actual object pointer. + instance = *(void**)(instance); + } + } + + if (classData->m_typeId == subgraphInterfaceAssetTypeID) + { + auto asset = reinterpret_cast*>(instance); + auto id = asset->GetId(); + dependentAssets.push_back(SourceHandle(nullptr, id.m_guid, {})); + } + + return true; + }; + + AZ::SerializeContext* serializeContext = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext); + AZ_Assert(serializeContext, "LoadEditorAssetTree() ailed to retrieve serialize context!"); + + const ScriptCanvasEditor::Graph* graph = handle.Get(); + serializeContext->EnumerateObject(graph, beginElementCB, nullptr, AZ::SerializeContext::ENUM_ACCESS_FOR_READ); + + EditorAssetTree result; + + for (auto& dependentAsset : dependentAssets) + { + auto loadDependentOutcome = LoadEditorAssetTree(dependentAsset, &result); + if (!loadDependentOutcome.IsSuccess()) + { + return AZ::Failure(AZStd::string::format("LoadEditorAssetTree failed to load graph from %s: %s" + , dependentAsset.ToString().c_str(), loadDependentOutcome.GetError().c_str())); + } + + result.m_dependencies.push_back(loadDependentOutcome.TakeValue()); + } + + if (parent) + { + result.SetParent(*parent); + } + + result.m_asset = AZStd::move(handle); + return AZ::Success(result); + } + + AZ::Outcome LoadFromFile(AZStd::string_view path) + { + namespace JSRU = AZ::JsonSerializationUtils; + + auto fileStringOutcome = AZ::Utils::ReadFile(path); + if (!fileStringOutcome) + { + return AZ::Failure(fileStringOutcome.TakeError()); + } + + const auto& asString = fileStringOutcome.GetValue(); + ScriptCanvas::DataPtr scriptCanvasData = aznew ScriptCanvas::ScriptCanvasData(); + if (!scriptCanvasData) + { + return AZ::Failure(AZStd::string("failed to allocate ScriptCanvas::ScriptCanvasData after loading source file")); + } + + AZ::SerializeContext* serializeContext = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext); + if (!serializeContext) + { + return AZ::Failure(AZStd::string("no serialize context available to properly parse source file")); + } + + // attempt JSON deserialization... + auto jsonResult = LoadDataFromJson(*scriptCanvasData, AZStd::string_view{ asString.begin(), asString.size() }, *serializeContext); + if (!jsonResult.IsSuccess()) + { + // ...try legacy xml as a failsafe + AZ::IO::ByteContainerStream byteStream(&asString); + if (!AZ::Utils::LoadObjectFromStreamInPlace + ( byteStream + , *scriptCanvasData + , serializeContext + , AZ::ObjectStream::FilterDescriptor(nullptr, AZ::ObjectStream::FILTERFLAG_IGNORE_UNKNOWN_CLASSES))) + { + return AZ::Failure(AZStd::string::format("XML and JSON load attempts failed: %s", jsonResult.GetError().c_str())); + } + } + + if (auto entity = scriptCanvasData->GetScriptCanvasEntity()) + { + AZ_Assert(entity->GetState() == AZ::Entity::State::Constructed, "Entity loaded in bad state"); + AZ::u64 entityId = + aznumeric_caster(ScriptCanvas::MathNodeUtilities::GetRandomIntegral(1, std::numeric_limits::max())); + entity->SetId(AZ::EntityId(entityId)); + + auto graph = entity->FindComponent(); + graph->MarkOwnership(*scriptCanvasData); + + entity->Init(); + entity->Activate(); + } + else + { + return AZ::Failure(AZStd::string("Loaded script canvas file was missing a necessary Entity.")); + } + + return AZ::Success(ScriptCanvasEditor::SourceHandle(scriptCanvasData, path)); + } + + AZ::Outcome SaveToStream(const SourceHandle& source, AZ::IO::GenericStream& stream) + { + namespace JSRU = AZ::JsonSerializationUtils; + + if (!source.IsGraphValid()) + { + return AZ::Failure(AZStd::string("no source graph to save")); + } + + if (source.Path().empty()) + { + return AZ::Failure(AZStd::string("no destination path specified")); + } + + AZ::SerializeContext* serializeContext = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext); + if (!serializeContext) + { + return AZ::Failure(AZStd::string("no serialize context available to properly save source file")); + } + + auto graphData = source.Get()->GetOwnership(); + if (!graphData) + { + return AZ::Failure(AZStd::string("source is missing save container")); + } + + if (graphData->GetEditorGraph() != source.Get()) + { + return AZ::Failure(AZStd::string("source save container refers to incorrect graph")); + } + + auto saveTarget = graphData->ModGraph(); + if (!saveTarget || !saveTarget->GetGraphData()) + { + return AZ::Failure(AZStd::string("source save container failed to return serializable graph data")); + } + + AZ::JsonSerializerSettings settings; + settings.m_metadata.Create(); + auto listeners = settings.m_metadata.Find(); + AZ_Assert(listeners, "Failed to create SerializationListeners"); + ScriptCanvasFileHandlingCpp::CollectNodes(saveTarget->GetGraphData()->m_nodes, *listeners); + settings.m_keepDefaults = false; + settings.m_serializeContext = serializeContext; + + for (auto listener : *listeners) + { + listener->OnSerialize(); + } + + auto saveOutcome = JSRU::SaveObjectToStream(graphData.get(), stream, nullptr, &settings); + if (!saveOutcome.IsSuccess()) + { + return AZ::Failure(AZStd::string::format("JSON serialization failed to save source: %s", saveOutcome.GetError().c_str())); + } + + return AZ::Success(); + } +} diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp index 165007b79b..a20a6e54a1 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp @@ -19,8 +19,7 @@ namespace ScriptCanvasEditor { ScriptCanvasMemoryAsset::ScriptCanvasMemoryAsset() - : m_isSaving(false) - , m_sourceInError(false) + : m_sourceInError(false) { m_undoState = AZStd::make_unique(this); } @@ -279,14 +278,11 @@ namespace ScriptCanvasEditor EditorGraphNotificationBus::Handler::BusDisconnect(); EditorGraphNotificationBus::Handler::BusConnect(m_scriptCanvasId); - - m_undoHelper = AZStd::make_unique(*this); } - ScriptCanvasEditor::Widget::CanvasWidget* ScriptCanvasMemoryAsset::CreateView(QWidget* parent) + ScriptCanvasEditor::Widget::CanvasWidget* ScriptCanvasMemoryAsset::CreateView(QWidget* /*parent*/) { - m_canvasWidget = new Widget::CanvasWidget(m_fileAssetId, parent); - return m_canvasWidget; + return nullptr; } void ScriptCanvasMemoryAsset::ClearView() @@ -430,68 +426,13 @@ namespace ScriptCanvasEditor } } - void ScriptCanvasMemoryAsset::SourceFileFailed(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid) + void ScriptCanvasMemoryAsset::SourceFileFailed(AZStd::string /*relativePath*/, AZStd::string /*scanFolder*/, AZ::Uuid) { - AZStd::string fullPath; - AzFramework::StringFunc::Path::Join(scanFolder.data(), relativePath.data(), fullPath); - AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::NormalizePath, fullPath); - auto assetPathIdIt = AZStd::find(m_pendingSave.begin(), m_pendingSave.end(), fullPath); - - if (assetPathIdIt != m_pendingSave.end()) - { - if (m_onSaveCallback) - { - m_onSaveCallback(false, m_inMemoryAsset.Get(), AZ::Data::AssetId()); - m_onSaveCallback = nullptr; - } - - m_pendingSave.erase(assetPathIdIt); - } } - void ScriptCanvasMemoryAsset::SavingComplete(const AZStd::string& streamName, AZ::Uuid sourceAssetId) + void ScriptCanvasMemoryAsset::SavingComplete(const AZStd::string& /*streamName*/, AZ::Uuid /*sourceAssetId*/) { - AZStd::string normPath = streamName; - AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::NormalizePath, normPath); - - auto assetPathIdIt = AZStd::find(m_pendingSave.begin(), m_pendingSave.end(), normPath); - if (assetPathIdIt != m_pendingSave.end()) - { - AZ::Data::AssetId previousFileAssetId; - - if (sourceAssetId != m_fileAssetId.m_guid) - { - previousFileAssetId = m_fileAssetId; - - // The source file has changed, store the AssetId to the canonical asset on file - SetFileAssetId(sourceAssetId); - - } - else if (!m_fileAssetId.IsValid()) - { - SetFileAssetId(sourceAssetId); - } - - m_formerGraphIdPair = AZStd::make_pair(m_scriptCanvasId, m_graphId); - - m_fileState = Tracker::ScriptCanvasFileState::UNMODIFIED; - - m_pendingSave.erase(assetPathIdIt); - - m_absolutePath = m_saveAsPath; - m_saveAsPath.clear(); - - // Connect to the source asset's bus to monitor for situations we may need to handle - AZ::Data::AssetBus::MultiHandler::BusConnect(m_inMemoryAsset.GetId()); - AZ::Data::AssetBus::MultiHandler::BusConnect(m_fileAssetId); - - if (m_onSaveCallback) - { - m_onSaveCallback(true, m_inMemoryAsset.Get(), previousFileAssetId); - m_onSaveCallback = nullptr; - } - } } void ScriptCanvasMemoryAsset::FinalizeAssetSave(bool, const AzToolsFramework::SourceControlFileInfo& fileInfo, const AZ::Data::AssetStreamInfo& saveInfo, Callbacks::OnSave onSaveCallback) @@ -525,19 +466,13 @@ namespace ScriptCanvasEditor UndoNotificationBus::Broadcast(&UndoNotifications::OnCanRedoChanged, m_undoState->m_undoStack->CanRedo()); } - void ScriptCanvasMemoryAsset::SetFileAssetId(const AZ::Data::AssetId& fileAssetId) + void ScriptCanvasMemoryAsset::SetFileAssetId(const AZ::Data::AssetId& /*fileAssetId*/) { - m_fileAssetId = fileAssetId; - if (m_canvasWidget) - { - m_canvasWidget->SetAssetId(fileAssetId); - } } void ScriptCanvasMemoryAsset::SignalFileStateChanged() { - MemoryAssetNotificationBus::Event(m_fileAssetId, &MemoryAssetNotifications::OnFileStateChanged, GetFileState()); } AZStd::string ScriptCanvasMemoryAsset::MakeTemporaryFilePathForSave(AZStd::string_view targetFilename) @@ -604,27 +539,8 @@ namespace ScriptCanvasEditor // AssetSaveFinalizer ////////////////////////////////////// - bool AssetSaveFinalizer::ValidateStatus(const AzToolsFramework::SourceControlFileInfo& fileInfo) + bool AssetSaveFinalizer::ValidateStatus(const AzToolsFramework::SourceControlFileInfo& /*fileInfo*/) { - auto fileIO = AZ::IO::FileIOBase::GetInstance(); - if (fileInfo.IsLockedByOther()) - { - AZ_Error("Script Canvas", !fileInfo.IsLockedByOther(), "The file is already exclusively opened by another user: %s", fileInfo.m_filePath.data()); - AZStd::invoke(m_onSave, false, m_inMemoryAsset, m_fileAssetId); - return false; - } - else if (fileInfo.IsReadOnly() && fileIO->Exists(fileInfo.m_filePath.c_str())) - { - AZ_Error("Script Canvas", !fileInfo.IsReadOnly(), "File %s is read-only. It cannot be saved." - " If this file is in Perforce it may not have been checked out by the Source Control API.", fileInfo.m_filePath.data()); - AZStd::invoke(m_onSave, false, m_inMemoryAsset, m_fileAssetId); - return false; - } - else if (m_saving) - { - AZ_Warning("Script Canvas", false, "Trying to save the same file twice. Will result in one save callback being ignored."); - return false; - } return true; } diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.h b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.h index 9665e8ec64..45647eba1b 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.h +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.h @@ -29,6 +29,8 @@ #include #include +#include + namespace ScriptCanvasEditor { @@ -172,7 +174,6 @@ namespace ScriptCanvasEditor bool IsSourceInError() const; - void OnSourceAssetFinalized(const AZStd::string& fullPath, AZ::Uuid sourceAssetId); void SavingComplete(const AZStd::string& fullPath, AZ::Uuid sourceAssetId); AZ::Data::AssetId GetSourceUuid() const { return m_sourceUuid; } @@ -320,7 +321,6 @@ namespace ScriptCanvasEditor //! The undo helper is an object that implements the Undo behaviors AZStd::unique_ptr m_undoHelper; - bool m_isSaving; bool m_sourceInError; AZ::Data::AssetId m_sourceUuid; diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.cpp index 388da67987..f125a4cbc9 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.cpp @@ -9,13 +9,19 @@ #include "ScriptCanvasUndoHelper.h" #include "ScriptCanvasMemoryAsset.h" #include +#include namespace ScriptCanvasEditor { - UndoHelper::UndoHelper(ScriptCanvasMemoryAsset& memoryAsset) - : m_memoryAsset(memoryAsset) + UndoHelper::UndoHelper() + : m_undoState(this) { - UndoRequestBus::Handler::BusConnect(memoryAsset.GetScriptCanvasId()); + } + + UndoHelper::UndoHelper(Graph* graph) + : m_undoState(this) + { + SetSource(graph); } UndoHelper::~UndoHelper() @@ -23,15 +29,21 @@ namespace ScriptCanvasEditor UndoRequestBus::Handler::BusDisconnect(); } + void UndoHelper::SetSource(Graph* graph) + { + m_graph = graph; + UndoRequestBus::Handler::BusConnect(graph->GetScriptCanvasId()); + } + ScriptCanvasEditor::UndoCache* UndoHelper::GetSceneUndoCache() { - return m_memoryAsset.GetUndoState()->m_undoCache.get(); + return m_undoState.m_undoCache.get(); } ScriptCanvasEditor::UndoData UndoHelper::CreateUndoData() { - AZ::EntityId graphCanvasGraphId = m_memoryAsset.GetGraphId(); - ScriptCanvas::ScriptCanvasId scriptCanvasId = m_memoryAsset.GetScriptCanvasId(); + AZ::EntityId graphCanvasGraphId = m_graph->GetGraphCanvasGraphId(); + ScriptCanvas::ScriptCanvasId scriptCanvasId = m_graph->GetScriptCanvasId(); GraphCanvas::GraphModelRequestBus::Event(graphCanvasGraphId, &GraphCanvas::GraphModelRequests::OnSaveDataDirtied, graphCanvasGraphId); @@ -56,17 +68,17 @@ namespace ScriptCanvasEditor void UndoHelper::BeginUndoBatch(AZStd::string_view label) { - m_memoryAsset.GetUndoState()->BeginUndoBatch(label); + m_undoState.BeginUndoBatch(label); } void UndoHelper::EndUndoBatch() { - m_memoryAsset.GetUndoState()->EndUndoBatch(); + m_undoState.EndUndoBatch(); } void UndoHelper::AddUndo(AzToolsFramework::UndoSystem::URSequencePoint* sequencePoint) { - if (SceneUndoState* sceneUndoState = m_memoryAsset.GetUndoState()) + if (SceneUndoState* sceneUndoState = &m_undoState) { if (!sceneUndoState->m_currentUndoBatch) { @@ -82,22 +94,22 @@ namespace ScriptCanvasEditor void UndoHelper::AddGraphItemChangeUndo(AZStd::string_view undoLabel) { GraphItemChangeCommand* command = aznew GraphItemChangeCommand(undoLabel); - command->Capture(m_memoryAsset, true); - command->Capture(m_memoryAsset, false); + command->Capture(m_graph, true); + command->Capture(m_graph, false); AddUndo(command); } void UndoHelper::AddGraphItemAdditionUndo(AZStd::string_view undoLabel) { GraphItemAddCommand* command = aznew GraphItemAddCommand(undoLabel); - command->Capture(m_memoryAsset, false); + command->Capture(m_graph, false); AddUndo(command); } void UndoHelper::AddGraphItemRemovalUndo(AZStd::string_view undoLabel) { GraphItemRemovalCommand* command = aznew GraphItemRemovalCommand(undoLabel); - command->Capture(m_memoryAsset, true); + command->Capture(m_graph, true); AddUndo(command); } @@ -105,7 +117,7 @@ namespace ScriptCanvasEditor { AZ_PROFILE_FUNCTION(ScriptCanvas); - SceneUndoState* sceneUndoState = m_memoryAsset.GetUndoState(); + SceneUndoState* sceneUndoState = &m_undoState; if (sceneUndoState) { AZ_Warning("Script Canvas", !sceneUndoState->m_currentUndoBatch, "Script Canvas Editor has an open undo batch when performing a redo operation"); @@ -125,7 +137,7 @@ namespace ScriptCanvasEditor { AZ_PROFILE_FUNCTION(ScriptCanvas); - SceneUndoState* sceneUndoState = m_memoryAsset.GetUndoState(); + SceneUndoState* sceneUndoState = &m_undoState; if (sceneUndoState) { AZ_Warning("Script Canvas", !sceneUndoState->m_currentUndoBatch, "Script Canvas Editor has an open undo batch when performing a redo operation"); @@ -143,7 +155,7 @@ namespace ScriptCanvasEditor void UndoHelper::Reset() { - if (SceneUndoState* sceneUndoState = m_memoryAsset.GetUndoState()) + if (SceneUndoState* sceneUndoState = &m_undoState) { AZ_Warning("Script Canvas", !sceneUndoState->m_currentUndoBatch, "Script Canvas Editor has an open undo batch when resetting the undo stack"); sceneUndoState->m_undoStack->Reset(); @@ -162,17 +174,23 @@ namespace ScriptCanvasEditor bool UndoHelper::CanUndo() const { - return m_memoryAsset.GetUndoState()->m_undoStack->CanUndo(); + return m_undoState.m_undoStack->CanUndo(); } bool UndoHelper::CanRedo() const { - return m_memoryAsset.GetUndoState()->m_undoStack->CanRedo(); + return m_undoState.m_undoStack->CanRedo(); + } + + void UndoHelper::OnUndoStackChanged() + { + UndoNotificationBus::Broadcast(&UndoNotifications::OnCanUndoChanged, m_undoState.m_undoStack->CanUndo()); + UndoNotificationBus::Broadcast(&UndoNotifications::OnCanRedoChanged, m_undoState.m_undoStack->CanRedo()); } void UndoHelper::UpdateCache() { - ScriptCanvas::ScriptCanvasId scriptCanvasId = m_memoryAsset.GetScriptCanvasId(); + ScriptCanvas::ScriptCanvasId scriptCanvasId = m_graph->GetScriptCanvasId(); UndoCache* undoCache = nullptr; UndoRequestBus::EventResult(undoCache, scriptCanvasId, &UndoRequests::GetSceneUndoCache); diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.h b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.h index 7bf5c8b630..e2d4f008fa 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.h +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.h @@ -8,22 +8,27 @@ #pragma once #include +#include namespace ScriptCanvasEditor { - class ScriptCanvasMemoryAsset; // Helper class that provides the implementation for UndoRequestBus - class UndoHelper : UndoRequestBus::Handler + class UndoHelper + : public UndoRequestBus::Handler + , public AzToolsFramework::UndoSystem::IUndoNotify { public: - UndoHelper(ScriptCanvasMemoryAsset& memoryAsset); + UndoHelper(); + UndoHelper(Graph* source); ~UndoHelper(); UndoCache* GetSceneUndoCache() override; UndoData CreateUndoData() override; + void SetSource(Graph* source); + void BeginUndoBatch(AZStd::string_view label) override; void EndUndoBatch() override; void AddUndo(AzToolsFramework::UndoSystem::URSequencePoint* seqPoint) override; @@ -41,6 +46,7 @@ namespace ScriptCanvasEditor bool CanRedo() const override; private: + void OnUndoStackChanged() override; void UpdateCache(); @@ -51,7 +57,7 @@ namespace ScriptCanvasEditor }; Status m_status = Status::Idle; - - ScriptCanvasMemoryAsset& m_memoryAsset; + SceneUndoState m_undoState; + Graph* m_graph = nullptr; }; } diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp index 77f791483b..b50457adbf 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp @@ -77,6 +77,7 @@ AZ_POP_DISABLE_WARNING #include #include #include +#include #include #include #include @@ -480,6 +481,7 @@ namespace ScriptCanvasEditor ScriptCanvas::Graph::Activate(); PostActivate(); + m_undoHelper.SetSource(this); } void Graph::Deactivate() @@ -489,7 +491,7 @@ namespace ScriptCanvasEditor EditorGraphRequestBus::Handler::BusDisconnect(); SceneCounterRequestBus::Handler::BusDisconnect(); NodeCreationNotificationBus::Handler::BusDisconnect(); - + AZ::SystemTickBus::Handler::BusDisconnect(); GraphCanvas::SceneNotificationBus::Handler::BusDisconnect(); GraphCanvas::GraphModelRequestBus::Handler::BusDisconnect(); @@ -1029,18 +1031,50 @@ namespace ScriptCanvasEditor { AZStd::any* connectionUserData = nullptr; GraphCanvas::ConnectionRequestBus::EventResult(connectionUserData, connectionId, &GraphCanvas::ConnectionRequests::GetUserData); - auto scConnectionId = connectionUserData && connectionUserData->is() ? *AZStd::any_cast(connectionUserData) : AZ::EntityId(); + auto scConnectionId = connectionUserData && connectionUserData->is() + ? *AZStd::any_cast(connectionUserData) + : AZ::EntityId(); - ScriptCanvas::Connection* connection = AZ::EntityUtils::FindFirstDerivedComponent(scConnectionId); - - if (connection) + if (ScriptCanvas::Connection* connection = AZ::EntityUtils::FindFirstDerivedComponent(scConnectionId)) { - ScriptCanvas::GraphNotificationBus::Event(GetScriptCanvasId(), &ScriptCanvas::GraphNotifications::OnDisonnectionComplete, connectionId); - + ScriptCanvas::GraphNotificationBus::Event + ( GetScriptCanvasId() + , &ScriptCanvas::GraphNotifications::OnDisonnectionComplete + , connectionId); DisconnectById(scConnectionId); } } + ScriptCanvas::DataPtr Graph::Create() + { + if (AZ::Entity* entity = aznew AZ::Entity("Script Canvas Graph")) + { + auto graph = entity->CreateComponent(); + entity->CreateComponent(graph->GetScriptCanvasId()); + + if (ScriptCanvas::DataPtr data = aznew ScriptCanvas::ScriptCanvasData()) + { + data->m_scriptCanvasEntity.reset(entity); + graph->MarkOwnership(*data); + entity->Init(); + entity->Activate(); + return data; + } + } + + return nullptr; + } + + void Graph::MarkOwnership(ScriptCanvas::ScriptCanvasData& owner) + { + m_owner = &owner; + } + + ScriptCanvas::DataPtr Graph::GetOwnership() const + { + return const_cast(this)->m_owner; + } + bool Graph::CreateConnection(const GraphCanvas::ConnectionId& connectionId, const GraphCanvas::Endpoint& sourcePoint, const GraphCanvas::Endpoint& targetPoint) { if (!sourcePoint.IsValid() || !targetPoint.IsValid()) @@ -1323,7 +1357,8 @@ namespace ScriptCanvasEditor void Graph::SignalDirty() { - GeneralRequestBus::Broadcast(&GeneralRequests::SignalSceneDirty, GetAssetId()); + SourceHandle handle(m_owner, {}, {}); + GeneralRequestBus::Broadcast(&GeneralRequests::SignalSceneDirty, handle); } void Graph::HighlightNodesByType(const ScriptCanvas::NodeTypeIdentifier& nodeTypeIdentifier) @@ -3354,11 +3389,6 @@ namespace ScriptCanvasEditor } } - void Graph::SetAssetType(AZ::Data::AssetType assetType) - { - m_assetType = assetType; - } - void Graph::ReportError(const ScriptCanvas::Node& node, const AZStd::string& errorSource, const AZStd::string& errorMessage) { AzQtComponents::ToastConfiguration toastConfiguration(AzQtComponents::ToastType::Error, errorSource.c_str(), errorMessage.c_str()); @@ -3463,7 +3493,7 @@ namespace ScriptCanvasEditor m_focusHelper.SetActiveGraph(GetGraphCanvasGraphId()); } - bool Graph::UpgradeGraph(const AZ::Data::Asset& asset, UpgradeRequest request, bool isVerbose) + bool Graph::UpgradeGraph(SourceHandle& asset, UpgradeRequest request, bool isVerbose) { m_upgradeSM.SetAsset(asset); m_upgradeSM.SetVerbose(isVerbose); diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp index 043e034062..3ad2580d3c 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp @@ -6,7 +6,6 @@ * */ - #include #include #include @@ -14,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -21,23 +21,26 @@ #include #include #include +#include #include #include #include +#include #include #include #include #include +#include #include #include - namespace EditorScriptCanvasComponentCpp { enum Version { PrefabIntegration = 10, - + InternalDev, + AddSourceHandle, // add description above Current }; @@ -128,7 +131,7 @@ namespace ScriptCanvasEditor } ScriptCanvasBuilder::BuildVariableOverrides overrides; - overrides.m_source = AZ::Data::Asset(assetHolder.GetAssetId(), assetHolder.GetAssetType(), assetHolder.GetAssetHint());; + overrides.m_source = SourceHandle(nullptr, assetHolder.GetAssetId().m_guid, {}); for (auto& variable : editableData.GetVariables()) { @@ -142,6 +145,25 @@ namespace ScriptCanvasEditor } } + if (rootElement.GetVersion() < EditorScriptCanvasComponentCpp::Version::AddSourceHandle) + { + ScriptCanvasAssetHolder assetHolder; + if (!rootElement.FindSubElementAndGetData(AZ_CRC_CE("m_assetHolder"), assetHolder)) + { + AZ_Error("ScriptCanvas", false, "EditorScriptCanvasComponent conversion failed: could not retrieve old 'm_assetHolder'"); + return false; + } + + auto assetId = assetHolder.GetAssetId(); + auto path = assetHolder.GetAssetHint(); + + if (!rootElement.AddElementWithData(serializeContext, "runtimeDataOverrides", SourceHandle(nullptr, assetId.m_guid, path))) + { + AZ_Error("ScriptCanvas", false, "EditorScriptCanvasComponent conversion failed: failed to add 'sourceHandle'"); + return false; + } + } + return true; } @@ -153,9 +175,9 @@ namespace ScriptCanvasEditor serializeContext->Class() ->Version(EditorScriptCanvasComponentCpp::Version::Current, &EditorScriptCanvasComponentVersionConverter) ->Field("m_name", &EditorScriptCanvasComponent::m_name) - ->Field("m_assetHolder", &EditorScriptCanvasComponent::m_scriptCanvasAssetHolder) ->Field("runtimeDataIsValid", &EditorScriptCanvasComponent::m_runtimeDataIsValid) ->Field("runtimeDataOverrides", &EditorScriptCanvasComponent::m_variableOverrides) + ->Field("sourceHandle", &EditorScriptCanvasComponent::m_sourceHandle) ; if (AZ::EditContext* editContext = serializeContext->GetEditContext()) @@ -171,29 +193,34 @@ namespace ScriptCanvasEditor ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("UI", 0x27ff46b0)) ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Level", 0x9aeacc13)) ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/scripting/script-canvas/") - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorScriptCanvasComponent::m_scriptCanvasAssetHolder, "Script Canvas Asset", "Script Canvas asset associated with this component") - ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorScriptCanvasComponent::m_sourceHandle, "Script Canvas Source File", "Script Canvas source file associated with this component") + ->Attribute("BrowseIcon", ":/stylesheet/img/UI20/browse-edit-select-files.svg") + ->Attribute("EditButton", "") + ->Attribute("EditDescription", "Open in Script Canvas Editor") + ->Attribute("EditCallback", &EditorScriptCanvasComponent::OpenEditor) + ->Attribute(AZ::Edit::Attributes::AssetPickerTitle, "Script Canvas") + ->Attribute(AZ::Edit::Attributes::SourceAssetFilterPattern, "*.scriptcanvas") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorScriptCanvasComponent::OnFileSelectionChanged) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorScriptCanvasComponent::m_variableOverrides, "Properties", "Script Canvas Graph Properties") - ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ; } } + + if (AZ::JsonRegistrationContext* jsonContext = azrtti_cast(context)) + { + jsonContext->Serializer()->HandlesType(); + } } EditorScriptCanvasComponent::EditorScriptCanvasComponent() - : EditorScriptCanvasComponent(AZ::Data::Asset()) + : EditorScriptCanvasComponent(SourceHandle()) { } - EditorScriptCanvasComponent::EditorScriptCanvasComponent(AZ::Data::Asset asset) - : m_scriptCanvasAssetHolder() + EditorScriptCanvasComponent::EditorScriptCanvasComponent(const SourceHandle& sourceHandle) + : m_sourceHandle(sourceHandle) { - if (asset.GetId().IsValid()) - { - m_scriptCanvasAssetHolder.SetAsset(asset.GetId()); - } - - m_scriptCanvasAssetHolder.SetScriptChangedCB([this](AZ::Data::AssetId assetId) { OnScriptCanvasAssetChanged(assetId); }); } EditorScriptCanvasComponent::~EditorScriptCanvasComponent() @@ -209,50 +236,34 @@ namespace ScriptCanvasEditor void EditorScriptCanvasComponent::UpdateName() { - AZ::Data::AssetId assetId = m_scriptCanvasAssetHolder.GetAssetId(); - if (assetId.IsValid()) + SetName(m_sourceHandle.Path().Filename().Native()); + } + + void EditorScriptCanvasComponent::OpenEditor(const AZ::Data::AssetId&, const AZ::Data::AssetType&) + { + AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); + + AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); + + if (m_sourceHandle.IsDescriptionValid()) { - // Pathname from the asset doesn't seem to return a value unless the asset has been loaded up once(which isn't done until we try to show it). - // Using the Job system to determine the asset name instead. - AZ::Outcome jobOutcome = AZ::Failure(); - AzToolsFramework::AssetSystemJobRequestBus::BroadcastResult(jobOutcome, &AzToolsFramework::AssetSystemJobRequestBus::Events::GetAssetJobsInfoByAssetID, assetId, false, false); - - AZStd::string assetPath; - AZStd::string assetName; - - if (jobOutcome.IsSuccess()) + GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, m_sourceHandle, Tracker::ScriptCanvasFileState::UNMODIFIED, -1); + + if (!openOutcome) { - AzToolsFramework::AssetSystem::JobInfoContainer& jobs = jobOutcome.GetValue(); - - // Get the asset relative path - if (!jobs.empty()) - { - assetPath = jobs[0].m_sourceFile; - } - - // Get the asset file name - assetName = assetPath; - - if (!assetPath.empty()) - { - AzFramework::StringFunc::Path::GetFileName(assetPath.c_str(), assetName); - SetName(assetName); - } + AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data()); } } - } - - void EditorScriptCanvasComponent::OpenEditor() - { - m_scriptCanvasAssetHolder.OpenEditor(); - } - - void EditorScriptCanvasComponent::CloseGraph() - { - AZ::Data::AssetId assetId = m_scriptCanvasAssetHolder.GetAssetId(); - if (assetId.IsValid()) + else if (GetEntityId().IsValid()) { - GeneralRequestBus::Broadcast(&GeneralRequests::CloseScriptCanvasAsset, assetId); + AzToolsFramework::EntityIdList selectedEntityIds; + AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(selectedEntityIds, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities); + + // Going to bypass the multiple selected entities flow for right now. + if (selectedEntityIds.size() == 1) + { + GeneralRequestBus::Broadcast(&GeneralRequests::CreateScriptCanvasAssetFor, AZStd::make_pair(GetEntityId(), GetId())); + } } } @@ -261,7 +272,11 @@ namespace ScriptCanvasEditor EditorComponentBase::Init(); AzFramework::AssetCatalogEventBus::Handler::BusConnect(); AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusConnect(); - m_scriptCanvasAssetHolder.Init(GetEntityId(), GetId()); + } + + void EditorScriptCanvasComponent::InitializeSource(const SourceHandle& sourceHandle) + { + m_sourceHandle = sourceHandle; } //========================================================================= @@ -269,6 +284,8 @@ namespace ScriptCanvasEditor { EditorComponentBase::Activate(); + AzToolsFramework::AssetSystemBus::Handler::BusConnect(); + AZ::EntityId entityId = GetEntityId(); EditorContextMenuRequestBus::Handler::BusConnect(entityId); @@ -277,19 +294,15 @@ namespace ScriptCanvasEditor EditorScriptCanvasComponentLoggingBus::Handler::BusConnect(entityId); EditorLoggingComponentNotificationBus::Broadcast(&EditorLoggingComponentNotifications::OnEditorScriptCanvasComponentActivated, GetNamedEntityId(), GetGraphIdentifier()); - AZ::Data::AssetId fileAssetId = m_scriptCanvasAssetHolder.GetAssetId(); + CompleteDescriptionInPlace(m_sourceHandle); - if (fileAssetId.IsValid()) - { - AssetTrackerNotificationBus::Handler::BusConnect(fileAssetId); - AzToolsFramework::ToolsApplicationNotificationBus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree_NewContent); - } + AzToolsFramework::ToolsApplicationNotificationBus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree_NewContent); } //========================================================================= void EditorScriptCanvasComponent::Deactivate() { - AssetTrackerNotificationBus::Handler::BusDisconnect(); + AzToolsFramework::AssetSystemBus::Handler::BusDisconnect(); EditorScriptCanvasComponentLoggingBus::Handler::BusDisconnect(); EditorLoggingComponentNotificationBus::Broadcast(&EditorLoggingComponentNotifications::OnEditorScriptCanvasComponentDeactivated, GetNamedEntityId(), GetGraphIdentifier()); @@ -303,10 +316,11 @@ namespace ScriptCanvasEditor void EditorScriptCanvasComponent::BuildGameEntityData() { using namespace ScriptCanvasBuilder; + CompleteDescriptionInPlace(m_sourceHandle); m_runtimeDataIsValid = false; - auto assetTreeOutcome = LoadEditorAssetTree(m_scriptCanvasAssetHolder.GetAssetId(), m_scriptCanvasAssetHolder.GetAssetHint()); + auto assetTreeOutcome = LoadEditorAssetTree(m_sourceHandle); if (!assetTreeOutcome.IsSuccess()) { AZ_Warning("ScriptCanvas", false, "EditorScriptCanvasComponent::BuildGameEntityData failed: %s", assetTreeOutcome.GetError().c_str()); @@ -344,7 +358,8 @@ namespace ScriptCanvasEditor if (!m_runtimeDataIsValid) { - AZ_Error("ScriptCanvasBuilder", false, "Runtime information did not build for ScriptCanvas Component using asset: %s", m_scriptCanvasAssetHolder.GetAssetId().ToString().c_str()); + AZ_Error("ScriptCanvasBuilder", false, "Runtime information did not build for ScriptCanvas Component using asset: %s" + , m_sourceHandle.ToString().c_str()); return; } @@ -352,168 +367,132 @@ namespace ScriptCanvasEditor runtimeComponent->TakeRuntimeDataOverrides(ConvertToRuntime(m_variableOverrides)); } - void EditorScriptCanvasComponent::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId) - { - if (m_removedCatalogId == assetId) - { - if (!m_scriptCanvasAssetHolder.GetAssetId().IsValid()) - { - SetPrimaryAsset(assetId); - m_removedCatalogId.SetInvalid(); - } - } - } - void EditorScriptCanvasComponent::OnCatalogAssetRemoved(const AZ::Data::AssetId& removedAssetId, const AZ::Data::AssetInfo& /*assetInfo*/) - { - AZ::Data::AssetId assetId = m_scriptCanvasAssetHolder.GetAssetId(); - if (assetId == removedAssetId) - { - m_removedCatalogId = assetId; - SetPrimaryAsset({}); - } - } - void EditorScriptCanvasComponent::SetPrimaryAsset(const AZ::Data::AssetId& assetId) { - m_scriptCanvasAssetHolder.ClearAsset(); + m_sourceHandle = SourceHandle(nullptr, assetId.m_guid, {}); - if (assetId.IsValid()) + auto completeAsset = CompleteDescription(m_sourceHandle); + if (completeAsset) { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); - - if (memoryAsset) - { - m_scriptCanvasAssetHolder.SetAsset(memoryAsset->GetFileAssetId()); - OnScriptCanvasAssetChanged(memoryAsset->GetFileAssetId()); - SetName(memoryAsset->GetTabName()); - } - else - { - auto scriptCanvasAsset = AZ::Data::AssetManager::Instance().FindAsset(assetId, AZ::Data::AssetLoadBehavior::Default); - if (scriptCanvasAsset) - { - m_scriptCanvasAssetHolder.SetAsset(assetId); - } - } + m_sourceHandle = *completeAsset; } + OnScriptCanvasAssetChanged(SourceChangeDescription::SelectionChanged); + SetName(m_sourceHandle.Path().Filename().Native()); AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues); } AZ::Data::AssetId EditorScriptCanvasComponent::GetAssetId() const { - return m_scriptCanvasAssetHolder.GetAssetId(); + return m_sourceHandle.Id(); } - AZ::EntityId EditorScriptCanvasComponent::GetGraphEntityId() const + AZ::u32 EditorScriptCanvasComponent::OnFileSelectionChanged() { - AZ::EntityId scriptCanvasEntityId; - AZ::Data::AssetId assetId = m_scriptCanvasAssetHolder.GetAssetId(); - - if (assetId.IsValid()) - { - AssetTrackerRequestBus::BroadcastResult(scriptCanvasEntityId, &AssetTrackerRequests::GetScriptCanvasId, assetId); - } - - return scriptCanvasEntityId; + m_sourceHandle = SourceHandle(nullptr, m_sourceHandle.Path()); + CompleteDescriptionInPlace(m_sourceHandle); + m_previousHandle = {}; + m_removedHandle = {}; + OnScriptCanvasAssetChanged(SourceChangeDescription::SelectionChanged); + return AZ::Edit::PropertyRefreshLevels::EntireTree; } - - void EditorScriptCanvasComponent::OnAssetReady(const ScriptCanvasMemoryAsset::pointer asset) + + void EditorScriptCanvasComponent::OnScriptCanvasAssetChanged(SourceChangeDescription changeDescription) { - OnScriptCanvasAssetReady(asset); - } - - void EditorScriptCanvasComponent::OnAssetSaved(const ScriptCanvasMemoryAsset::pointer asset, bool isSuccessful) - { - if (isSuccessful) - { - OnScriptCanvasAssetReady(asset); - } - } - - void EditorScriptCanvasComponent::OnAssetReloaded(const ScriptCanvasMemoryAsset::pointer asset) - { - OnScriptCanvasAssetReady(asset); - } - - void EditorScriptCanvasComponent::OnScriptCanvasAssetChanged(AZ::Data::AssetId assetId) - { - AssetTrackerNotificationBus::Handler::BusDisconnect(); ScriptCanvas::GraphIdentifier newIdentifier = GetGraphIdentifier(); - newIdentifier.m_assetId = assetId; + newIdentifier.m_assetId = m_sourceHandle.Id(); ScriptCanvas::GraphIdentifier oldIdentifier = GetGraphIdentifier(); - oldIdentifier.m_assetId = m_previousAssetId; + oldIdentifier.m_assetId = m_previousHandle.Id(); EditorLoggingComponentNotificationBus::Broadcast(&EditorLoggingComponentNotifications::OnAssetSwitched, GetNamedEntityId(), newIdentifier, oldIdentifier); - m_previousAssetId = m_scriptCanvasAssetHolder.GetAssetId(); + m_previousHandle = m_sourceHandle.Describe(); - // Only clear our variables when we are given a new asset id - // or when the asset was explicitly set to empty. - // - // i.e. do not clear variables when we lose the catalog asset. - if ((assetId.IsValid() && assetId != m_removedCatalogId) - || (!assetId.IsValid() && !m_removedCatalogId.IsValid())) + if (changeDescription == SourceChangeDescription::SelectionChanged) { ClearVariables(); } - if (assetId.IsValid()) + if (m_sourceHandle.IsDescriptionValid()) { - AssetTrackerNotificationBus::Handler::BusConnect(assetId); - - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); - if (memoryAsset && memoryAsset->GetAsset().GetStatus() == AZ::Data::AssetData::AssetStatus::Ready) + if (!m_sourceHandle.Get()) { - OnScriptCanvasAssetReady(memoryAsset); + if (auto loaded = LoadFromFile(m_sourceHandle.Path().c_str()); loaded.IsSuccess()) + { + m_sourceHandle = SourceHandle(loaded.TakeValue(), m_sourceHandle.Id(), m_sourceHandle.Path().c_str()); + } + } + + if (m_sourceHandle.Get()) + { + UpdatePropertyDisplay(m_sourceHandle); } } AzToolsFramework::ToolsApplicationNotificationBus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree_NewContent); } - void EditorScriptCanvasComponent::OnStartPlayInEditor() + void EditorScriptCanvasComponent::SetAssetId(const SourceHandle& assetId) { - ScriptCanvas::Execution::PerformanceStatisticsEBus::Broadcast(&ScriptCanvas::Execution::PerformanceStatisticsBus::ClearSnaphotStatistics); - } - - void EditorScriptCanvasComponent::OnStopPlayInEditor() - { - AZ::ScriptSystemRequestBus::Broadcast(&AZ::ScriptSystemRequests::GarbageCollect); - } - - void EditorScriptCanvasComponent::SetAssetId(const AZ::Data::AssetId& assetId) - { - if (m_scriptCanvasAssetHolder.GetAssetId() != assetId) + if (m_sourceHandle.Describe() != assetId.Describe()) { // Invalidate the previously removed catalog id if we are setting a new asset id - m_removedCatalogId.SetInvalid(); - SetPrimaryAsset(assetId); + m_removedHandle = {}; + SetPrimaryAsset(assetId.Id()); + } + } + + void EditorScriptCanvasComponent::SourceFileChanged([[maybe_unused]] AZStd::string relativePath + , [[maybe_unused]] AZStd::string scanFolder, [[maybe_unused]] AZ::Uuid fileAssetId) + { + if (fileAssetId == m_sourceHandle.Id()) + { + if (auto handle = CompleteDescription(SourceHandle(nullptr, fileAssetId, {}))) + { + m_sourceHandle = *handle; + // consider queueing on tick bus + OnScriptCanvasAssetChanged(SourceChangeDescription::Modified); + } + } + } + + void EditorScriptCanvasComponent::SourceFileRemoved([[maybe_unused]] AZStd::string relativePath + , [[maybe_unused]] AZStd::string scanFolder, [[maybe_unused]] AZ::Uuid fileAssetId) + { + if (fileAssetId == m_sourceHandle.Id()) + { + m_removedHandle = m_sourceHandle; + OnScriptCanvasAssetChanged(SourceChangeDescription::Removed); + } + } + + void EditorScriptCanvasComponent::SourceFileFailed([[maybe_unused]] AZStd::string relativePath + , [[maybe_unused]] AZStd::string scanFolder, [[maybe_unused]] AZ::Uuid fileAssetId) + { + if (fileAssetId == m_sourceHandle.Id()) + { + m_removedHandle = m_sourceHandle; + OnScriptCanvasAssetChanged(SourceChangeDescription::Error); } } bool EditorScriptCanvasComponent::HasAssetId() const { - return m_scriptCanvasAssetHolder.GetAssetId().IsValid(); + return !m_sourceHandle.Id().IsNull(); } ScriptCanvas::GraphIdentifier EditorScriptCanvasComponent::GetGraphIdentifier() const { // For now we don't want to deal with disambiguating duplicates of the same script running on one entity. // Should that change we need to add the component id back into this. - return ScriptCanvas::GraphIdentifier(m_scriptCanvasAssetHolder.GetAssetId(), 0); + return ScriptCanvas::GraphIdentifier(m_sourceHandle.Id(), 0); } - void EditorScriptCanvasComponent::OnScriptCanvasAssetReady(const ScriptCanvasMemoryAsset::pointer memoryAsset) + void EditorScriptCanvasComponent::UpdatePropertyDisplay(const SourceHandle& sourceHandle) { - if (memoryAsset->GetFileAssetId() == m_scriptCanvasAssetHolder.GetAssetId()) + if (sourceHandle.IsGraphValid()) { - auto assetData = memoryAsset->GetAsset(); - [[maybe_unused]] AZ::Entity* scriptCanvasEntity = assetData->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "This graph must have a valid entity"); BuildGameEntityData(); UpdateName(); AzToolsFramework::ToolsApplicationNotificationBus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree_NewContent); diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp index 650be01387..2cd2dda89e 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp @@ -17,6 +17,7 @@ AZ_POP_DISABLE_WARNING #include #include #include +#include #include #include @@ -30,6 +31,62 @@ AZ_POP_DISABLE_WARNING namespace ScriptCanvasEditor { + AZStd::optional CompleteDescription(const SourceHandle& source) + { + if (source.IsDescriptionValid()) + { + return source; + } + + AzToolsFramework::AssetSystemRequestBus::Events* assetSystem = AzToolsFramework::AssetSystemRequestBus::FindFirstHandler(); + if (assetSystem) + { + AZStd::string watchFolder; + AZ::Data::AssetInfo assetInfo; + + if (!source.Id().IsNull()) + { + if (assetSystem->GetSourceInfoBySourceUUID(source.Id(), assetInfo, watchFolder)) + { + AZ::IO::Path watchPath(watchFolder); + AZ::IO::Path assetInfoPath(assetInfo.m_relativePath); + SourceHandle fullPathHandle(nullptr, assetInfo.m_assetId.m_guid, watchPath / assetInfoPath); + + if (assetSystem->GetSourceInfoBySourcePath(fullPathHandle.Path().c_str(), assetInfo, watchFolder) && assetInfo.m_assetId.IsValid()) + { + AZ_Warning("ScriptCanvas", assetInfo.m_assetId.m_guid == source.Id(), "SourceHandle completion produced conflicting AssetId."); + auto path = fullPathHandle.Path(); + return SourceHandle(source, assetInfo.m_assetId.m_guid, path.MakePreferred()); + } + } + } + + if (!source.Path().empty()) + { + if (assetSystem->GetSourceInfoBySourcePath(source.Path().c_str(), assetInfo, watchFolder) && assetInfo.m_assetId.IsValid()) + { + return SourceHandle(source, assetInfo.m_assetId.m_guid, source.Path()); + } + } + } + + + return AZStd::nullopt; + } + + bool CompleteDescriptionInPlace(SourceHandle& source) + { + if (auto completed = CompleteDescription(source)) + { + source = *completed; + return true; + } + else + { + return false; + } + } + ////////////////////////// // NodeIdentifierFactory ////////////////////////// diff --git a/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp b/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp index 0e5f11fa40..fec813b0c1 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp @@ -438,10 +438,11 @@ namespace ScriptCanvasEditor if (nodeConfig.IsValid()) { ScriptCanvas::NodeUpdateSlotReport nodeUpdateSlotReport; + auto nodeEntity = node->GetEntityId(); auto nodeOutcome = graph->ReplaceNodeByConfig(node, nodeConfig, nodeUpdateSlotReport); if (nodeOutcome.IsSuccess()) { - ScriptCanvas::MergeUpdateSlotReport(node->GetEntityId(), sm->m_updateReport, nodeUpdateSlotReport); + ScriptCanvas::MergeUpdateSlotReport(nodeEntity, sm->m_updateReport, nodeUpdateSlotReport); sm->m_allNodes.erase(node); sm->m_outOfDateNodes.erase(node); @@ -675,20 +676,20 @@ namespace ScriptCanvasEditor RegisterState(ParseGraph); } - void EditorGraphUpgradeMachine::SetAsset(const AZ::Data::Asset& asset) + void EditorGraphUpgradeMachine::SetAsset(SourceHandle& asset) { if (m_asset != asset) { m_asset = asset; - SetDebugPrefix(asset.GetHint()); + SetDebugPrefix(asset.Path().c_str()); } } void EditorGraphUpgradeMachine::OnComplete(IState::ExitStatus exitStatus) { UpgradeNotificationsBus::Broadcast(&UpgradeNotifications::OnGraphUpgradeComplete, m_asset, exitStatus == IState::ExitStatus::Skipped); - - m_asset = {}; + // releasing the asset at this stage of the system tick causes a memory crash + // m_asset = {}; } ////////////////////////////////////////////////////////////////////// diff --git a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.h b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.h index 4d1be42d35..8593429b92 100644 --- a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.h +++ b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.h @@ -11,6 +11,7 @@ #include #include #include +#include namespace ScriptCanvas { diff --git a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl index 05541196f7..74d0f76dce 100644 --- a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl +++ b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl @@ -75,7 +75,7 @@ namespace ScriptCanvasEditor AZ_Assert(loadResult.m_runtimeAsset, "failed to load dependent asset"); AZ::Outcome luaAssetOutcome = AZ::Failure(AZStd::string("lua asset creation for function failed")); - ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(luaAssetOutcome, &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateLuaAsset, loadResult.m_editorAsset, loadResult.m_graphPath); + ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(luaAssetOutcome, &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateLuaAsset, loadResult.m_editorAsset, loadResult.m_editorAsset.Path().c_str()); AZ_Assert(luaAssetOutcome.IsSuccess(), "failed to create Lua asset"); AZStd::string modulePath = namespacePath[0].data(); @@ -112,18 +112,19 @@ namespace ScriptCanvasEditor AZ_INLINE LoadTestGraphResult LoadTestGraph(AZStd::string_view graphPath) { - AZ::Data::Asset editorAsset; - ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(editorAsset, &ScriptCanvasEditor::EditorAssetConversionBusTraits::LoadAsset, graphPath); - - if (editorAsset.GetData()) + if (auto loadFileOutcome = LoadFromFile(graphPath); loadFileOutcome.IsSuccess()) { - AZ::Outcome< AZ::Data::Asset, AZStd::string> assetOutcome = AZ::Failure(AZStd::string("asset creation failed")); - ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(assetOutcome, &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateRuntimeAsset, editorAsset); + auto& source = loadFileOutcome.GetValue(); + auto testableSource = SourceHandle(source, AZ::Uuid::CreateRandom(), source.Path().c_str()); + + AZ::Outcome, AZStd::string> assetOutcome(AZ::Failure(AZStd::string("asset create failed"))); + ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(assetOutcome + , &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateRuntimeAsset, testableSource); + if (assetOutcome.IsSuccess()) { LoadTestGraphResult result; - result.m_graphPath = graphPath; - result.m_editorAsset = editorAsset; + result.m_editorAsset = AZStd::move(testableSource); result.m_runtimeAsset = assetOutcome.GetValue(); result.m_entity = AZStd::make_unique("Loaded Graph"); return result; @@ -164,8 +165,7 @@ namespace ScriptCanvasEditor reporter.SetExecutionMode(mode); LoadTestGraphResult loadResult; - loadResult.m_graphPath = asset.GetHint().c_str(); - loadResult.m_editorAsset = asset; + loadResult.m_editorAsset = SourceHandle(nullptr, assetId.m_guid, asset.GetHint()); AZ::EntityId scriptCanvasId; loadResult.m_entity = AZStd::make_unique("Loaded test graph"); loadResult.m_runtimeAsset = runtimeAsset; @@ -206,7 +206,8 @@ namespace ScriptCanvasEditor { ScopedOutputSuppression outputSuppressor; AZ::Outcome luaAssetOutcome = AZ::Failure(AZStd::string("lua asset creation failed")); - ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(luaAssetOutcome, &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateLuaAsset, loadResult.m_editorAsset, loadResult.m_graphPath); + ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(luaAssetOutcome + , &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateLuaAsset, loadResult.m_editorAsset, loadResult.m_editorAsset.Path().c_str()); reporter.MarkParseAttemptMade(); if (luaAssetOutcome.IsSuccess()) @@ -220,6 +221,8 @@ namespace ScriptCanvasEditor { RuntimeDataOverrides runtimeDataOverrides; runtimeDataOverrides.m_runtimeAsset = loadResult.m_runtimeAsset; + runtimeDataOverrides.m_runtimeAsset.SetHint("original"); + runtimeDataOverrides.m_runtimeAsset.Get()->m_runtimeData.m_script.SetHint("original"); #if defined(LINUX) ////////////////////////////////////////////////////////////////////////// // Temporarily disable testing on the Linux build until the file name casing discrepancy @@ -265,6 +268,10 @@ namespace ScriptCanvasEditor RuntimeDataOverrides dependencyRuntimeDataOverrides; dependencyRuntimeDataOverrides.m_runtimeAsset = dependency.runtimeAsset; + AZStd::string dependencyHint = AZStd::string::format("dependency_%d", index); + dependencyRuntimeDataOverrides.m_runtimeAsset.SetHint(dependencyHint); + dependencyRuntimeDataOverrides.m_runtimeAsset.Get()->m_runtimeData.m_script.SetHint(dependencyHint); + runtimeDataOverrides.m_dependencies.push_back(dependencyRuntimeDataOverrides); RuntimeData& dependencyData = dependencyDataBuffer[index]; diff --git a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasTraceUtilities.h b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasTraceUtilities.h index a87f4450c2..458852132d 100644 --- a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasTraceUtilities.h +++ b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasTraceUtilities.h @@ -27,6 +27,7 @@ #include #include #include +#include namespace AZ { @@ -45,11 +46,10 @@ namespace ScriptCanvasEditor struct LoadTestGraphResult { - AZStd::string_view m_graphPath; AZStd::unique_ptr m_entity; ScriptCanvas::RuntimeComponent* m_runtimeComponent = nullptr; bool m_nativeFunctionFound = false; - AZ::Data::Asset m_editorAsset; + SourceHandle m_editorAsset; AZ::Data::Asset m_runtimeAsset; AZ::Data::Asset m_scriptAsset; }; @@ -161,7 +161,7 @@ namespace ScriptCanvasEditor struct ScopedOutputSuppression { - ScopedOutputSuppression(bool suppressState = true) + ScopedOutputSuppression([[maybe_unused]] bool suppressState = true) { AZ::Debug::TraceMessageBus::BroadcastResult(m_oldSuppression, &AZ::Debug::TraceMessageEvents::OnOutput, "", ""); TraceSuppressionBus::Broadcast(&TraceSuppressionRequests::SuppressAllOutput, suppressState); diff --git a/Gems/ScriptCanvas/Code/Editor/GraphCanvas/Components/NodeDescriptors/FunctionNodeDescriptorComponent.cpp b/Gems/ScriptCanvas/Code/Editor/GraphCanvas/Components/NodeDescriptors/FunctionNodeDescriptorComponent.cpp index db41fa70ca..f80c6dde21 100644 --- a/Gems/ScriptCanvas/Code/Editor/GraphCanvas/Components/NodeDescriptors/FunctionNodeDescriptorComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/GraphCanvas/Components/NodeDescriptors/FunctionNodeDescriptorComponent.cpp @@ -97,7 +97,8 @@ namespace ScriptCanvasEditor } AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); - GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, assetInfo.m_assetId, -1); + GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset + , SourceHandle( nullptr, assetInfo.m_assetId.m_guid, {} ), Tracker::ScriptCanvasFileState::UNMODIFIED, -1); return openOutcome.IsSuccess(); } diff --git a/Gems/ScriptCanvas/Code/Editor/GraphCanvas/Components/NodeDescriptors/ScriptEventReceiverEventNodeDescriptorComponent.cpp b/Gems/ScriptCanvas/Code/Editor/GraphCanvas/Components/NodeDescriptors/ScriptEventReceiverEventNodeDescriptorComponent.cpp index ab231ae637..43bfc4b221 100644 --- a/Gems/ScriptCanvas/Code/Editor/GraphCanvas/Components/NodeDescriptors/ScriptEventReceiverEventNodeDescriptorComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/GraphCanvas/Components/NodeDescriptors/ScriptEventReceiverEventNodeDescriptorComponent.cpp @@ -190,7 +190,7 @@ namespace ScriptCanvasEditor { scriptCanvasSlot = eventHandler->GetSlot(slotId); - int& index = (scriptCanvasSlot->IsData() && scriptCanvasSlot->IsInput()) ? paramIndex : outputIndex; + int& index = (scriptCanvasSlot && scriptCanvasSlot->IsData() && scriptCanvasSlot->IsInput()) ? paramIndex : outputIndex; if (scriptCanvasSlot && scriptCanvasSlot->IsVisible()) { diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasAssetHandler.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasAssetHandler.h index f29d5aa9cb..a0e00b40fd 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasAssetHandler.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasAssetHandler.h @@ -20,11 +20,6 @@ namespace AZ namespace ScriptCanvasEditor { - AZ::Outcome LoadScriptCanvasDataFromJson - ( ScriptCanvas::ScriptCanvasData& dataTarget - , AZStd::string_view source - , AZ::SerializeContext& serializeContext); - /** * Manages editor Script Canvas graph assets. */ diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.cpp b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.cpp index 6da134ed6a..efb20e3518 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.cpp @@ -7,17 +7,4 @@ */ #include -#include -namespace ScriptCanvas -{ - Graph* ScriptCanvasData::ModGraph() - { - return AZ::EntityUtils::FindFirstDerivedComponent(m_scriptCanvasEntity.get()); - } - - const Graph* ScriptCanvasData::GetGraph() const - { - return AZ::EntityUtils::FindFirstDerivedComponent(m_scriptCanvasEntity.get()); - } -} diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.h index f4b02b56b6..7597da9081 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.h @@ -13,27 +13,5 @@ namespace ScriptCanvas { - class ScriptCanvasData - { - public: - - AZ_RTTI(ScriptCanvasData, "{1072E894-0C67-4091-8B64-F7DB324AD13C}"); - AZ_CLASS_ALLOCATOR(ScriptCanvasData, AZ::SystemAllocator, 0); - ScriptCanvasData() {} - virtual ~ScriptCanvasData() {} - ScriptCanvasData(ScriptCanvasData&& other); - ScriptCanvasData& operator=(ScriptCanvasData&& other); - - static void Reflect(AZ::ReflectContext* reflectContext); - - AZ::Entity* GetScriptCanvasEntity() const { return m_scriptCanvasEntity.get(); } - - Graph* ModGraph(); - - const Graph* GetGraph() const; - - AZStd::unique_ptr m_scriptCanvasEntity; - private: - ScriptCanvasData(const ScriptCanvasData&) = delete; - }; + } diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h new file mode 100644 index 0000000000..bd3d2b9f0a --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include + +namespace AZ +{ + class SerializeContext; +} + +namespace ScriptCanvas +{ + class ScriptCanvasData; +} + +namespace ScriptCanvasEditor +{ + class EditorAssetTree + { + public: + AZ_CLASS_ALLOCATOR(EditorAssetTree, AZ::SystemAllocator, 0); + + EditorAssetTree* m_parent = nullptr; + AZStd::vector m_dependencies; + SourceHandle m_asset; + + EditorAssetTree* ModRoot(); + + void SetParent(EditorAssetTree& parent); + + AZStd::string ToString(size_t depth = 0) const; + }; + + AZ::Outcome LoadFromFile(AZStd::string_view path); + + AZ::Outcome LoadDataFromJson + ( ScriptCanvas::ScriptCanvasData& dataTarget + , AZStd::string_view source + , AZ::SerializeContext& serializeContext); + + AZ::Outcome LoadEditorAssetTree(SourceHandle handle, EditorAssetTree* parent = nullptr); + + AZ::Outcome SaveToStream(const SourceHandle& source, AZ::IO::GenericStream& stream); +} diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h index 7e7b600081..b1fd291a1b 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h @@ -26,6 +26,8 @@ #include #include +#include + namespace GraphCanvas { class GraphCanvasTreeItem; @@ -70,7 +72,7 @@ namespace ScriptCanvasEditor static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; using BusIdType = AZ::EntityId; - virtual void SetAssetId(const AZ::Data::AssetId& assetId) = 0; + virtual void SetAssetId(const SourceHandle& assetId) = 0; virtual bool HasAssetId() const = 0; }; @@ -89,40 +91,13 @@ namespace ScriptCanvasEditor }; using EditorContextMenuRequestBus = AZ::EBus; - - class EditorScriptCanvasAssetNotifications : public AZ::EBusTraits - { - public: - static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; - using BusIdType = AZ::Data::AssetId; - - //! Notification which fires after an EditorGraph has received it's on AssetReady callback - //! \param scriptCanvasAsset Script Canvas asset which is now ready for use in the Editor - virtual void OnScriptCanvasAssetReady(const AZ::Data::Asset& /*scriptCanvasAsset*/) {}; - - //! Notification which fires after an EditorGraph has received it's on AssetReloaded callback - //! \param scriptCanvasAsset Script Canvas asset which is now ready for use in the Editor - virtual void OnScriptCanvasAssetReloaded(const AZ::Data::Asset& /*scriptCanvaAsset */) {}; - - //! Notification which fires after an EditorGraph has received it's on AssetReady callback - //! \param AssetId AssetId of unloaded ScriptCanvas - virtual void OnScriptCanvasAssetUnloaded(const AZ::Data::AssetId& /*assetId*/) {}; - - //! Notification which fires after an EditorGraph has received an onAssetSaved callback - //! \param scriptCanvasAsset Script Canvas asset which was attempted to be saved - //! \param isSuccessful specified where the Script Canvas asset was successfully saved - virtual void OnScriptCanvasAssetSaved(const AZ::Data::AssetId) {}; - }; - using EditorScriptCanvasAssetNotificationBus = AZ::EBus; - + class EditorGraphRequests : public AZ::EBusTraits { public: static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; using BusIdType = ScriptCanvas::ScriptCanvasId; - virtual void SetAssetId(const AZ::Data::AssetId& assetId) = 0; - virtual void CreateGraphCanvasScene() = 0; virtual void ClearGraphCanvasScene() = 0; virtual GraphCanvas::GraphId GetGraphCanvasGraphId() const = 0; @@ -225,7 +200,7 @@ namespace ScriptCanvasEditor virtual void OnUpgradeStart() {} virtual void OnUpgradeCancelled() {} - virtual void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped = false) { (void)skipped; } + virtual void OnGraphUpgradeComplete(SourceHandle&, bool skipped = false) { (void)skipped; } }; using UpgradeNotificationsBus = AZ::EBus; diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h index 8fa7beab2b..5ec0ee1636 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h @@ -8,18 +8,16 @@ #pragma once -#include -#include -#include #include -#include +#include +#include +#include #include - +#include #include - -#include #include - +#include +#include #include class QLineEdit; @@ -49,6 +47,17 @@ namespace ScriptCanvasEditor struct CategoryInformation; struct NodePaletteModelInformation; + namespace Tracker + { + enum class ScriptCanvasFileState : AZ::s32 + { + NEW, + MODIFIED, + UNMODIFIED, + SOURCE_REMOVED, + INVALID = -1 + }; + } namespace Widget { @@ -70,16 +79,16 @@ namespace ScriptCanvasEditor //! Opens an existing graph and returns the tab index in which it was open in. //! \param File AssetId //! \return index of open tab if the asset was able to be open successfully or error message of why the open failed - virtual AZ::Outcome OpenScriptCanvasAsset(AZ::Data::AssetId scriptCanvasAssetId, int tabIndex = -1) = 0; - virtual AZ::Outcome OpenScriptCanvasAssetId(const AZ::Data::AssetId& scriptCanvasAsset) = 0; + virtual AZ::Outcome OpenScriptCanvasAsset(SourceHandle scriptCanvasAssetId, Tracker::ScriptCanvasFileState fileState, int tabIndex = -1) = 0; + virtual AZ::Outcome OpenScriptCanvasAssetId(const SourceHandle& scriptCanvasAsset, Tracker::ScriptCanvasFileState fileState) = 0; - virtual int CloseScriptCanvasAsset(const AZ::Data::AssetId&) = 0; + virtual int CloseScriptCanvasAsset(const SourceHandle&) = 0; virtual bool CreateScriptCanvasAssetFor(const TypeDefs::EntityComponentId& requestingComponent) = 0; - virtual bool IsScriptCanvasAssetOpen(const AZ::Data::AssetId& assetId) const = 0; + virtual bool IsScriptCanvasAssetOpen(const SourceHandle& assetId) const = 0; - virtual void OnChangeActiveGraphTab(AZ::Data::AssetId) {} + virtual void OnChangeActiveGraphTab(SourceHandle) {} virtual void CreateNewRuntimeAsset() = 0; @@ -103,12 +112,12 @@ namespace ScriptCanvasEditor return ScriptCanvas::ScriptCanvasId(); } - virtual GraphCanvas::GraphId FindGraphCanvasGraphIdByAssetId([[maybe_unused]] const AZ::Data::AssetId& assetId) const + virtual GraphCanvas::GraphId FindGraphCanvasGraphIdByAssetId([[maybe_unused]] const SourceHandle& assetId) const { return GraphCanvas::GraphId(); } - virtual ScriptCanvas::ScriptCanvasId FindScriptCanvasIdByAssetId([[maybe_unused]] const AZ::Data::AssetId& assetId) const + virtual ScriptCanvas::ScriptCanvasId FindScriptCanvasIdByAssetId([[maybe_unused]] const SourceHandle& assetId) const { return ScriptCanvas::ScriptCanvasId(); } @@ -126,7 +135,7 @@ namespace ScriptCanvasEditor virtual void DisconnectEndpoints(const AZ::EntityId& /*sceneId*/, const AZStd::vector& /*endpoints*/) {} virtual void PostUndoPoint(ScriptCanvas::ScriptCanvasId) = 0; - virtual void SignalSceneDirty(AZ::Data::AssetId) = 0; + virtual void SignalSceneDirty(SourceHandle) = 0; // Increment the value of the ignore undo point tracker virtual void PushPreventUndoStateUpdate() = 0; @@ -165,7 +174,7 @@ namespace ScriptCanvasEditor public: static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; - using BusIdType = AZ::Data::AssetId; + using BusIdType = SourceHandle; virtual void OnAssetVisualized() {}; virtual void OnAssetUnloaded() {}; diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h index 9913fa838b..9157aaeac9 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h @@ -34,6 +34,7 @@ #include #include +#include namespace ScriptCanvas { @@ -101,6 +102,8 @@ namespace ScriptCanvasEditor public: AZ_COMPONENT(Graph, "{4D755CA9-AB92-462C-B24F-0B3376F19967}", ScriptCanvas::Graph); + static ScriptCanvas::DataPtr Create(); + static void Reflect(AZ::ReflectContext* context); Graph(const ScriptCanvas::ScriptCanvasId& scriptCanvasId = AZ::Entity::MakeId()) @@ -138,10 +141,6 @@ namespace ScriptCanvasEditor void ReleaseVariableCounter(AZ::u32 variableCounter) override; //// - // RuntimeBus - AZ::Data::AssetId GetAssetId() const override { return m_assetId; } - //// - // GraphCanvas::GraphModelRequestBus void RequestUndoPoint() override; @@ -221,9 +220,6 @@ namespace ScriptCanvasEditor void OnGraphCanvasNodeCreated(const AZ::EntityId& nodeId) override; /////////////////////////// - // EditorGraphRequestBus - void SetAssetId(const AZ::Data::AssetId& assetId) override { m_assetId = assetId; } - void CreateGraphCanvasScene() override; void ClearGraphCanvasScene() override; void DisplayGraphCanvasScene() override; @@ -235,7 +231,7 @@ namespace ScriptCanvasEditor IfOutOfDate, Forced }; - bool UpgradeGraph(const AZ::Data::Asset& asset, UpgradeRequest request, bool isVerbose = true); + bool UpgradeGraph(SourceHandle& asset, UpgradeRequest request, bool isVerbose = true); void ConnectGraphCanvasBuses(); void DisconnectGraphCanvasBuses(); /////// @@ -302,12 +298,13 @@ namespace ScriptCanvasEditor void OnUndoRedoEnd() override; //// - void SetAssetType(AZ::Data::AssetType); - void ReportError(const ScriptCanvas::Node& node, const AZStd::string& errorSource, const AZStd::string& errorMessage) override; const GraphStatisticsHelper& GetNodeUsageStatistics() const; + void MarkOwnership(ScriptCanvas::ScriptCanvasData& owner); + ScriptCanvas::DataPtr GetOwnership() const; + // Finds and returns all nodes within the graph that are of the specified type template AZStd::vector GetNodesOfType() const @@ -384,12 +381,15 @@ namespace ScriptCanvasEditor GraphCanvas::NodeFocusCyclingHelper m_focusHelper; GraphStatisticsHelper m_statisticsHelper; + UndoHelper m_undoHelper; bool m_ignoreSaveRequests; //! Defaults to true to signal that this graph does not have the GraphCanvas stuff intermingled bool m_saveFormatConverted = true; - AZ::Data::AssetId m_assetId; + ScriptCanvasEditor::SourceHandle m_assetId; + // temporary step in cleaning up the graph / asset class structure. This reference is deliberately weak. + ScriptCanvas::ScriptCanvasData* m_owner; }; } diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h index 5dbe718eca..d797f8db08 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h @@ -9,12 +9,14 @@ #pragma once #include +#include #include #include #include #include #include #include +#include #include #include @@ -34,19 +36,23 @@ namespace ScriptCanvasEditor : public AzToolsFramework::Components::EditorComponentBase , private EditorContextMenuRequestBus::Handler , private AzFramework::AssetCatalogEventBus::Handler + , private AzToolsFramework::AssetSystemBus::Handler , private EditorScriptCanvasComponentLoggingBus::Handler , private EditorScriptCanvasComponentRequestBus::Handler - , private AssetTrackerNotificationBus::Handler , private AzToolsFramework::EditorEntityContextNotificationBus::Handler - { public: AZ_COMPONENT(EditorScriptCanvasComponent, "{C28E2D29-0746-451D-A639-7F113ECF5D72}", AzToolsFramework::Components::EditorComponentBase); + friend class AZ::EditorScriptCanvasComponentSerializer; + EditorScriptCanvasComponent(); - EditorScriptCanvasComponent(AZ::Data::Asset asset); + EditorScriptCanvasComponent(const SourceHandle& sourceHandle); ~EditorScriptCanvasComponent() override; + // sets the soure but does not attempt to load anything; + void InitializeSource(const SourceHandle& sourceHandle); + //===================================================================== // AZ::Component void Init() override; @@ -66,17 +72,16 @@ namespace ScriptCanvasEditor ScriptCanvas::GraphIdentifier GetGraphIdentifier() const override; //===================================================================== - void OpenEditor(); - void CloseGraph(); - - void SetName(const AZStd::string& name) { m_name = name; } + void OpenEditor(const AZ::Data::AssetId&, const AZ::Data::AssetType&); + + void SetName(AZStd::string_view name) { m_name = name; } const AZStd::string& GetName() const; AZ::EntityId GetEditorEntityId() const { return GetEntity() ? GetEntityId() : AZ::EntityId(); } AZ::NamedEntityId GetNamedEditorEntityId() const { return GetEntity() ? GetNamedEntityId() : AZ::NamedEntityId(); } //===================================================================== // EditorScriptCanvasComponentRequestBus - void SetAssetId(const AZ::Data::AssetId& assetId) override; + void SetAssetId(const SourceHandle& assetId) override; bool HasAssetId() const override; //===================================================================== @@ -84,23 +89,23 @@ namespace ScriptCanvasEditor // EditorContextMenuRequestBus AZ::Data::AssetId GetAssetId() const override; //===================================================================== - AZ::EntityId GetGraphEntityId() const; - - //===================================================================== - // AssetTrackerNotificationBus - void OnAssetReady(const ScriptCanvasMemoryAsset::pointer asset) override; - void OnAssetSaved(const ScriptCanvasMemoryAsset::pointer asset, bool isSuccessful) override; - void OnAssetReloaded(const ScriptCanvasMemoryAsset::pointer asset) override; - //===================================================================== + + //===================================================================== // EditorEntityContextNotificationBus - void OnStartPlayInEditor() override; - - void OnStopPlayInEditor() override; + protected: + enum class SourceChangeDescription : AZ::u8 + { + Error, + Modified, + Removed, + SelectionChanged, + }; + static void Reflect(AZ::ReflectContext* context); static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) @@ -118,25 +123,31 @@ namespace ScriptCanvasEditor (void)incompatible; } - void OnCatalogAssetAdded(const AZ::Data::AssetId& assetId) override; - void OnCatalogAssetRemoved(const AZ::Data::AssetId& assetId, const AZ::Data::AssetInfo& assetInfo) override; - void OnScriptCanvasAssetChanged(AZ::Data::AssetId assetId); + // complete the id, load call OnScriptCanvasAssetChanged + void SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid fileAssetId) override; + // update the display icon for failure, save the values in the graph + void SourceFileRemoved(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid fileAssetId) override; + void SourceFileFailed(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid fileAssetId) override; + + AZ::u32 OnFileSelectionChanged(); + + void OnScriptCanvasAssetChanged(SourceChangeDescription changeDescription); void UpdateName(); //===================================================================== - void OnScriptCanvasAssetReady(const ScriptCanvasMemoryAsset::pointer asset); + void UpdatePropertyDisplay(const SourceHandle& sourceHandle); //===================================================================== void BuildGameEntityData(); void ClearVariables(); private: - AZ::Data::AssetId m_removedCatalogId; - AZ::Data::AssetId m_previousAssetId; AZStd::string m_name; - ScriptCanvasAssetHolder m_scriptCanvasAssetHolder; bool m_runtimeDataIsValid = false; ScriptCanvasBuilder::BuildVariableOverrides m_variableOverrides; + SourceHandle m_sourceHandle; + SourceHandle m_previousHandle; + SourceHandle m_removedHandle; }; } diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponentSerializer.cpp b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponentSerializer.cpp new file mode 100644 index 0000000000..596c2d9dbf --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponentSerializer.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include + +namespace AZ +{ + AZ_CLASS_ALLOCATOR_IMPL(EditorScriptCanvasComponentSerializer, SystemAllocator, 0); + + JsonSerializationResult::Result EditorScriptCanvasComponentSerializer::Load + ( void* outputValue + , const Uuid& outputValueTypeId + , const rapidjson::Value& inputValue + , JsonDeserializerContext& context) + { + namespace JSR = JsonSerializationResult; + + AZ_Assert(outputValueTypeId == azrtti_typeid() + , "EditorScriptCanvasComponentSerializer Load against output typeID that was not EditorScriptCanvasComponent"); + AZ_Assert(outputValue, "EditorScriptCanvasComponentSerializer Load against null output"); + + // load as parent class + auto outputComponent = reinterpret_cast(outputValue); + JsonSerializationResult::ResultCode result = BaseJsonSerializer::Load(outputValue + , azrtti_typeid(), inputValue, context); + + // load child data one by one... + result.Combine(BaseJsonSerializer::Load(outputValue, outputValueTypeId, inputValue, context)); + + if (result.GetProcessing() != JSR::Processing::Halted) + { + result.Combine(ContinueLoadingFromJsonObjectField + ( &outputComponent->m_name + , azrtti_typeid(outputComponent->m_name) + , inputValue + , "m_name" + , context)); + + result.Combine(ContinueLoadingFromJsonObjectField + ( &outputComponent->m_runtimeDataIsValid + , azrtti_typeid(outputComponent->m_runtimeDataIsValid) + , inputValue + , "runtimeDataIsValid" + , context)); + + result.Combine(ContinueLoadingFromJsonObjectField + ( &outputComponent->m_variableOverrides + , azrtti_typeid(outputComponent->m_variableOverrides) + , inputValue + , "runtimeDataOverrides" + , context)); + + auto assetHolderMember = inputValue.FindMember("m_assetHolder"); + if (assetHolderMember == inputValue.MemberEnd()) + { + // file was saved with SourceHandle data + result.Combine(ContinueLoadingFromJsonObjectField + ( &outputComponent->m_sourceHandle + , azrtti_typeid(outputComponent->m_sourceHandle) + , inputValue + , "sourceHandle" + , context)); + } + else + { + // manually load the old asset info data + const rapidjson::Value& assetHolderValue = assetHolderMember->value; + if (auto assetMember = assetHolderValue.FindMember("m_asset"); assetMember != assetHolderValue.MemberEnd()) + { + const rapidjson::Value& assetValue = assetMember->value; + + AZ::Data::AssetId assetId{}; + if (auto assetIdMember = assetValue.FindMember("assetId"); assetIdMember != assetValue.MemberEnd()) + { + result.Combine(ContinueLoading(&assetId, azrtti_typeid(assetId), assetIdMember->value, context)); + } + + AZStd::string path{}; + if (auto pathMember = assetValue.FindMember("assetHint"); pathMember != assetValue.MemberEnd()) + { + result.Combine(ContinueLoading(&path, azrtti_typeid(path), pathMember->value, context)); + } + + if (result.GetProcessing() != JSR::Processing::Halted) + { + outputComponent->InitializeSource(ScriptCanvasEditor::SourceHandle(nullptr, assetId.m_guid, path)); + } + } + } + } + + return context.Report(result, result.GetProcessing() != JSR::Processing::Halted + ? "EditorScriptCanvasComponentSerializer Load finished loading EditorScriptCanvasComponent" + : "EditorScriptCanvasComponentSerializer Load failed to load EditorScriptCanvasComponent"); + } +} diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponentSerializer.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponentSerializer.h new file mode 100644 index 0000000000..68ad370997 --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponentSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include + +namespace AZ +{ + class EditorScriptCanvasComponentSerializer + : public BaseJsonSerializer + { + public: + AZ_RTTI(EditorScriptCanvasComponentSerializer, "{80B497B3-ABC1-4991-A3C4-047A8CB2C26C}", BaseJsonSerializer); + AZ_CLASS_ALLOCATOR_DECL; + + private: + JsonSerializationResult::Result Load + ( void* outputValue + , const Uuid& outputValueTypeId + , const rapidjson::Value& inputValue + , JsonDeserializerContext& context) override; + }; +} diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorUtils.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorUtils.h index 15100cbf4e..a4522198b7 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorUtils.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorUtils.h @@ -21,6 +21,13 @@ namespace GraphCanvas namespace ScriptCanvasEditor { + // If only the Path or the Id is valid, attempts to fill in the missing piece. + // If both Path and Id is valid, including after correction, returns the handle including source Data, + // otherwise, returns null + AZStd::optional CompleteDescription(const SourceHandle& source); + // if CompleteDescription() succeeds, sets the handle to the result, else does nothing + bool CompleteDescriptionInPlace(SourceHandle& source); + class Graph; class NodePaletteModel; diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/GraphUpgrade.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/GraphUpgrade.h index 817b883695..9fedc2d1f3 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/GraphUpgrade.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/GraphUpgrade.h @@ -102,9 +102,6 @@ namespace ScriptCanvasEditor void Log(const char* format, ...); private: - - bool m_verbose = true; - StateMachine* m_stateMachine; }; @@ -184,9 +181,9 @@ namespace ScriptCanvasEditor bool m_graphNeedsDirtying = false; Graph* m_graph = nullptr; - AZ::Data::Asset m_asset; + SourceHandle m_asset; - void SetAsset(const AZ::Data::Asset& asset); + void SetAsset(SourceHandle& assetasset); void OnComplete(IState::ExitStatus exitStatus) override; @@ -363,7 +360,7 @@ namespace ScriptCanvasEditor template void ScriptCanvasEditor::State::Log(const char* format, ...) { - if (m_verbose) + if (m_stateMachine->GetVerbose()) { char sBuffer[2048]; va_list ArgList; diff --git a/Gems/ScriptCanvas/Code/Editor/Nodes/NodeDisplayUtils.cpp b/Gems/ScriptCanvas/Code/Editor/Nodes/NodeDisplayUtils.cpp index 7913069243..8e273fd2fc 100644 --- a/Gems/ScriptCanvas/Code/Editor/Nodes/NodeDisplayUtils.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Nodes/NodeDisplayUtils.cpp @@ -393,7 +393,7 @@ namespace ScriptCanvasEditor::Nodes if (methodNode->HasBusID() && busId == slot.GetId() && slot.GetDescriptor() == ScriptCanvas::SlotDescriptors::DataIn()) { - key = Translation::GlobalKeys::EBusSenderIDKey; + key = ::Translation::GlobalKeys::EBusSenderIDKey; GraphCanvas::TranslationRequestBus::BroadcastResult(details, &GraphCanvas::TranslationRequests::GetDetails, key + ".details", details); } else @@ -508,7 +508,7 @@ namespace ScriptCanvasEditor::Nodes if (busNode->IsIDRequired() && slot->GetDescriptor() == ScriptCanvas::SlotDescriptors::DataIn()) { GraphCanvas::TranslationKey key; - key << Translation::GlobalKeys::EBusHandlerIDKey << "details"; + key << ::Translation::GlobalKeys::EBusHandlerIDKey << "details"; GraphCanvas::TranslationRequests::Details details; details.m_name = slot->GetName(); details.m_tooltip = slot->GetToolTip(); @@ -726,7 +726,7 @@ namespace ScriptCanvasEditor::Nodes if (busNode->IsIDRequired() && slot->GetDescriptor() == ScriptCanvas::SlotDescriptors::DataIn()) { GraphCanvas::TranslationKey key; - key << Translation::GlobalKeys::EBusHandlerIDKey << "details"; + key << ::Translation::GlobalKeys::EBusHandlerIDKey << "details"; GraphCanvas::TranslationRequests::Details details; GraphCanvas::TranslationRequestBus::BroadcastResult(details, &GraphCanvas::TranslationRequests::GetDetails, key, details); GraphCanvas::SlotRequestBus::Event(gcSlotId, &GraphCanvas::SlotRequests::SetDetails, details.m_name, details.m_tooltip); diff --git a/Gems/ScriptCanvas/Code/Editor/QtMetaTypes.h b/Gems/ScriptCanvas/Code/Editor/QtMetaTypes.h index 9058e27b03..5e413f0266 100644 --- a/Gems/ScriptCanvas/Code/Editor/QtMetaTypes.h +++ b/Gems/ScriptCanvas/Code/Editor/QtMetaTypes.h @@ -11,11 +11,13 @@ AZ_PUSH_DISABLE_WARNING(4251 4800 4244, "-Wunknown-warning-option") #include AZ_POP_DISABLE_WARNING +#include #include #include - // VariableId is a UUID typedef for now. So we don't want to double reflect the UUID. Q_DECLARE_METATYPE(AZ::Uuid); Q_DECLARE_METATYPE(AZ::Data::AssetId); Q_DECLARE_METATYPE(ScriptCanvas::Data::Type); Q_DECLARE_METATYPE(ScriptCanvas::VariableId); +Q_DECLARE_METATYPE(ScriptCanvasEditor::SourceHandle); + diff --git a/Gems/ScriptCanvas/Code/Editor/ReflectComponent.cpp b/Gems/ScriptCanvas/Code/Editor/ReflectComponent.cpp index a75671d0f8..7f2a170a4d 100644 --- a/Gems/ScriptCanvas/Code/Editor/ReflectComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/ReflectComponent.cpp @@ -31,6 +31,7 @@ namespace ScriptCanvasEditor { void ReflectComponent::Reflect(AZ::ReflectContext* context) { + SourceHandle::Reflect(context); ScriptCanvas::ScriptCanvasData::Reflect(context); ScriptCanvasAssetHolder::Reflect(context); EditorSettings::EditorWorkspace::Reflect(context); diff --git a/Gems/ScriptCanvas/Code/Editor/Settings.cpp b/Gems/ScriptCanvas/Code/Editor/Settings.cpp index 8d24a30aab..84744f77e3 100644 --- a/Gems/ScriptCanvas/Code/Editor/Settings.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Settings.cpp @@ -92,13 +92,11 @@ namespace ScriptCanvasEditor // WorkspaceAssetSaveData EditorWorkspace::WorkspaceAssetSaveData::WorkspaceAssetSaveData() - : m_assetType(azrtti_typeid()) { } - EditorWorkspace::WorkspaceAssetSaveData::WorkspaceAssetSaveData(const AZ::Data::AssetId& assetId) + EditorWorkspace::WorkspaceAssetSaveData::WorkspaceAssetSaveData(SourceHandle assetId) : m_assetId(assetId) - , m_assetType(azrtti_typeid()) { } @@ -108,7 +106,7 @@ namespace ScriptCanvasEditor { AZStd::vector assetSaveData; AZStd::vector assetIds; - auto subElement = rootDataElementNode.FindSubElement(AZ_CRC("ActiveAssetIds", 0xe445268a)); + auto subElement = rootDataElementNode.FindSubElement(AZ_CRC_CE("ActiveAssetIds")); if (subElement) { @@ -117,15 +115,21 @@ namespace ScriptCanvasEditor assetSaveData.reserve(assetIds.size()); for (const AZ::Data::AssetId& assetId : assetIds) { - assetSaveData.emplace_back(assetId); + assetSaveData.emplace_back(SourceHandle( nullptr, assetId.m_guid, "" )); } } } - rootDataElementNode.RemoveElementByName(AZ_CRC("ActiveAssetIds", 0xe445268a)); + rootDataElementNode.RemoveElementByName(AZ_CRC_CE("ActiveAssetIds")); rootDataElementNode.AddElementWithData(context, "ActiveAssetData", assetSaveData); } + if (rootDataElementNode.GetVersion() < 4) + { + rootDataElementNode.RemoveElementByName(AZ_CRC_CE("ActiveAssetIds")); + rootDataElementNode.RemoveElementByName(AZ_CRC_CE("FocusedAssetId")); + } + return true; } @@ -135,13 +139,12 @@ namespace ScriptCanvasEditor if (serialize) { serialize->Class() - ->Version(1) + ->Version(2) ->Field("AssetId", &WorkspaceAssetSaveData::m_assetId) - ->Field("AssetType", &WorkspaceAssetSaveData::m_assetType) ; serialize->Class() - ->Version(3, &EditorWorkspace::VersionConverter) + ->Version(4, &EditorWorkspace::VersionConverter) ->Field("m_storedWindowState", &EditorWorkspace::m_storedWindowState) ->Field("m_windowGeometry", &EditorWorkspace::m_windowGeometry) ->Field("FocusedAssetId", &EditorWorkspace::m_focusedAssetId) @@ -150,13 +153,13 @@ namespace ScriptCanvasEditor } } - void EditorWorkspace::ConfigureActiveAssets(AZ::Data::AssetId focussedAssetId, const AZStd::vector< WorkspaceAssetSaveData >& activeAssetData) + void EditorWorkspace::ConfigureActiveAssets(SourceHandle focussedAssetId, const AZStd::vector< WorkspaceAssetSaveData >& activeAssetData) { m_focusedAssetId = focussedAssetId; m_activeAssetData = activeAssetData; } - AZ::Data::AssetId EditorWorkspace::GetFocusedAssetId() const + SourceHandle EditorWorkspace::GetFocusedAssetId() const { return m_focusedAssetId; } diff --git a/Gems/ScriptCanvas/Code/Editor/Settings.h b/Gems/ScriptCanvas/Code/Editor/Settings.h index dee55f8272..27039d8a70 100644 --- a/Gems/ScriptCanvas/Code/Editor/Settings.h +++ b/Gems/ScriptCanvas/Code/Editor/Settings.h @@ -11,6 +11,7 @@ #include #include #include +#include // qdatastream.h(173): warning C4251: 'QDataStream::d': class 'QScopedPointer>' needs to have dll-interface to be used by clients of class 'QDataStream' // qwidget.h(858): warning C4800: 'uint': forcing value to bool 'true' or 'false' (performance warning) @@ -53,11 +54,10 @@ namespace ScriptCanvasEditor AZ_RTTI(WorkspaceAssetSaveData, "{927368CA-096F-4CF1-B2E0-1B9E4A93EA57}"); WorkspaceAssetSaveData(); - WorkspaceAssetSaveData(const AZ::Data::AssetId& assetId); + WorkspaceAssetSaveData(SourceHandle assetId); virtual ~WorkspaceAssetSaveData() = default; - AZ::Data::AssetId m_assetId; - AZ::Data::AssetType m_assetType; + SourceHandle m_assetId; }; @@ -69,9 +69,9 @@ namespace ScriptCanvasEditor EditorWorkspace() = default; - void ConfigureActiveAssets(AZ::Data::AssetId focusedAssetId, const AZStd::vector< WorkspaceAssetSaveData >& activeAssetIds); + void ConfigureActiveAssets(SourceHandle focusedAsset, const AZStd::vector< WorkspaceAssetSaveData >& activeAssetIds); - AZ::Data::AssetId GetFocusedAssetId() const; + SourceHandle GetFocusedAssetId() const; AZStd::vector< WorkspaceAssetSaveData > GetActiveAssetData() const; void Init(const QByteArray& windowState, const QByteArray& windowGeometry); @@ -79,7 +79,7 @@ namespace ScriptCanvasEditor void Clear() { - m_focusedAssetId.SetInvalid(); + m_focusedAssetId.Clear(); m_activeAssetData.clear(); } @@ -91,7 +91,7 @@ namespace ScriptCanvasEditor AZStd::vector m_windowGeometry; AZStd::vector m_windowState; - AZ::Data::AssetId m_focusedAssetId; + SourceHandle m_focusedAssetId; AZStd::vector< WorkspaceAssetSaveData > m_activeAssetData; }; diff --git a/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp b/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp index f901915fdb..758c395238 100644 --- a/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,7 @@ #include #include #include +#include #include #include @@ -119,6 +121,10 @@ namespace ScriptCanvasEditor PopulateEditorCreatableTypes(); AzToolsFramework::RegisterGenericComboBoxHandler(); + if (AzToolsFramework::PropertyTypeRegistrationMessages::Bus::FindFirstHandler()) + { + AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Broadcast(&AzToolsFramework::PropertyTypeRegistrationMessages::RegisterPropertyType, aznew SourceHandlePropertyHandler()); + } SystemRequestBus::Handler::BusConnect(); ScriptCanvasExecutionBus::Handler::BusConnect(); @@ -173,13 +179,11 @@ namespace ScriptCanvasEditor outCreatableTypes.insert(m_creatableTypes.begin(), m_creatableTypes.end()); } - void SystemComponent::CreateEditorComponentsOnEntity(AZ::Entity* entity, const AZ::Data::AssetType& assetType) + void SystemComponent::CreateEditorComponentsOnEntity(AZ::Entity* entity, [[maybe_unused]] const AZ::Data::AssetType& assetType) { if (entity) { auto graph = entity->CreateComponent(); - graph->SetAssetType(assetType); - entity->CreateComponent(graph->GetScriptCanvasId()); } } @@ -248,23 +252,25 @@ namespace ScriptCanvasEditor { continue; } - + entityMenu->setEnabled(true); - + usedIds.insert(assetId); - + AZStd::string rootPath; AZ::Data::AssetInfo assetInfo = AssetHelpers::GetAssetInfo(assetId, rootPath); - + AZStd::string displayName; AZ::StringFunc::Path::GetFileName(assetInfo.m_relativePath.c_str(), displayName); - + action = entityMenu->addAction(QString("%1").arg(QString(displayName.c_str()))); - + QObject::connect(action, &QAction::triggered, [assetId] { AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); - GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAsset, assetId, -1); + GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAsset + , SourceHandle(nullptr, assetId.m_guid, "") + , Tracker::ScriptCanvasFileState::UNMODIFIED, -1); }); } } @@ -301,7 +307,10 @@ namespace ScriptCanvasEditor return AzToolsFramework::AssetBrowser::SourceFileDetails(); } - void SystemComponent::AddSourceFileOpeners(const char* fullSourceFileName, [[maybe_unused]] const AZ::Uuid& sourceUUID, AzToolsFramework::AssetBrowser::SourceFileOpenerList& openers) + void SystemComponent::AddSourceFileOpeners + ( [[maybe_unused]] const char* fullSourceFileName + , [[maybe_unused]] const AZ::Uuid& sourceUUID + , [[maybe_unused]] AzToolsFramework::AssetBrowser::SourceFileOpenerList& openers) { using namespace AzToolsFramework; using namespace AzToolsFramework::AssetBrowser; @@ -322,16 +331,28 @@ namespace ScriptCanvasEditor if (fullDetails) { AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); - + AzToolsFramework::EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::OpenViewPane, "Script Canvas"); - GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, sourceUUIDInCall, -1); + GeneralRequestBus::BroadcastResult(openOutcome + , &GeneralRequests::OpenScriptCanvasAsset + , SourceHandle(nullptr, sourceUUIDInCall, ""), Tracker::ScriptCanvasFileState::UNMODIFIED, -1); } }; - openers.push_back({ "O3DE_ScriptCanvasEditor", "Open In Script Canvas Editor...", QIcon(), scriptCanvasEditorCallback }); + openers.push_back({ "O3DE_ScriptCanvasEditor", "Open In Script Canvas Editor...", QIcon(ScriptCanvasAssetDescription().GetIconPathImpl()), scriptCanvasEditorCallback }); } } + void SystemComponent::OnStartPlayInEditor() + { + ScriptCanvas::Execution::PerformanceStatisticsEBus::Broadcast(&ScriptCanvas::Execution::PerformanceStatisticsBus::ClearSnaphotStatistics); + } + + void SystemComponent::OnStopPlayInEditor() + { + AZ::ScriptSystemRequestBus::Broadcast(&AZ::ScriptSystemRequests::GarbageCollect); + } + void SystemComponent::OnUserSettingsActivated() { PopulateEditorCreatableTypes(); diff --git a/Gems/ScriptCanvas/Code/Editor/SystemComponent.h b/Gems/ScriptCanvas/Code/Editor/SystemComponent.h index 6f85b3c5a6..c2c42c5b9d 100644 --- a/Gems/ScriptCanvas/Code/Editor/SystemComponent.h +++ b/Gems/ScriptCanvas/Code/Editor/SystemComponent.h @@ -23,6 +23,7 @@ #include #include #include +#include namespace ScriptCanvasEditor { @@ -36,6 +37,8 @@ namespace ScriptCanvasEditor , private AZ::Data::AssetBus::MultiHandler , private AzToolsFramework::AssetSeedManagerRequests::Bus::Handler , private AzToolsFramework::EditorContextMenuBus::Handler + , private AzToolsFramework::EditorEntityContextNotificationBus::Handler + { public: AZ_COMPONENT(SystemComponent, "{1DE7A120-4371-4009-82B5-8140CB1D7B31}"); @@ -97,7 +100,12 @@ namespace ScriptCanvasEditor //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// - + + protected: + void OnStartPlayInEditor() override; + + void OnStopPlayInEditor() override; + private: SystemComponent(const SystemComponent&) = delete; diff --git a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.cpp b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.cpp index 4e3e0c85ad..944a5e667d 100644 --- a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -19,7 +20,6 @@ #include #include -#include namespace ScriptCanvasEditor { @@ -36,7 +36,7 @@ namespace ScriptCanvasEditor { } - void GraphItemCommand::Capture(ScriptCanvasMemoryAsset&, bool) + void GraphItemCommand::Capture(Graph*, bool) { } @@ -105,10 +105,10 @@ namespace ScriptCanvasEditor RestoreItem(m_redoState); } - void GraphItemChangeCommand::Capture(ScriptCanvasMemoryAsset& memoryAsset, bool captureUndo) + void GraphItemChangeCommand::Capture(Graph* graph, bool captureUndo) { - m_scriptCanvasId = memoryAsset.GetScriptCanvasId(); - m_graphCanvasGraphId = memoryAsset.GetGraphId(); + m_scriptCanvasId = graph->GetScriptCanvasId(); + m_graphCanvasGraphId = graph->GetGraphCanvasGraphId(); UndoCache* undoCache = nullptr; UndoRequestBus::EventResult(undoCache, m_scriptCanvasId, &UndoRequests::GetSceneUndoCache); @@ -204,9 +204,9 @@ namespace ScriptCanvasEditor RestoreItem(m_redoState); } - void GraphItemAddCommand::Capture(ScriptCanvasMemoryAsset& memoryAsset, bool) + void GraphItemAddCommand::Capture(Graph* graph, bool) { - GraphItemChangeCommand::Capture(memoryAsset, false); + GraphItemChangeCommand::Capture(graph, false); } //// Graph Item Removal Command @@ -225,8 +225,8 @@ namespace ScriptCanvasEditor RestoreItem(m_redoState); } - void GraphItemRemovalCommand::Capture(ScriptCanvasMemoryAsset& memoryAsset, bool) + void GraphItemRemovalCommand::Capture(Graph* graph, bool) { - GraphItemChangeCommand::Capture(memoryAsset, true); + GraphItemChangeCommand::Capture(graph, true); } } diff --git a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.h b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.h index e0f5adde7e..b9435d0702 100644 --- a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.h +++ b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.h @@ -46,7 +46,7 @@ namespace ScriptCanvasEditor void Undo() override; void Redo() override; - virtual void Capture(ScriptCanvasMemoryAsset& memoryAsset, bool captureUndo); + virtual void Capture(Graph* graph, bool captureUndo); bool Changed() const override; @@ -76,7 +76,7 @@ namespace ScriptCanvasEditor void Undo() override; void Redo() override; - void Capture(ScriptCanvasMemoryAsset& memoryAsset, bool captureUndo) override; + void Capture(Graph* graph, bool captureUndo) override; void RestoreItem(const AZStd::vector& restoreBuffer) override; @@ -103,7 +103,7 @@ namespace ScriptCanvasEditor void Undo() override; void Redo() override; - void Capture(ScriptCanvasMemoryAsset& memoryAsset, bool captureUndo) override; + void Capture(Graph* graph, bool captureUndo) override; protected: GraphItemAddCommand(const GraphItemAddCommand&) = delete; @@ -124,7 +124,7 @@ namespace ScriptCanvasEditor void Undo() override; void Redo() override; - void Capture(ScriptCanvasMemoryAsset& memoryAsset, bool captureUndo) override; + void Capture(Graph* graph, bool captureUndo) override; protected: GraphItemRemovalCommand(const GraphItemRemovalCommand&) = delete; diff --git a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasUndoManager.cpp b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasUndoManager.cpp index 4d24720227..5a01507352 100644 --- a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasUndoManager.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasUndoManager.cpp @@ -28,9 +28,9 @@ namespace ScriptCanvasEditor // SceneUndoState SceneUndoState::SceneUndoState(AzToolsFramework::UndoSystem::IUndoNotify* undoNotify) - : m_undoStack(AZStd::make_unique(c_undoLimit, undoNotify)) - , m_undoCache(AZStd::make_unique()) { + m_undoStack = AZStd::make_unique(c_undoLimit, undoNotify); + m_undoCache = AZStd::make_unique(); } void SceneUndoState::BeginUndoBatch(AZStd::string_view label) diff --git a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasUndoManager.h b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasUndoManager.h index 52d7b1de3e..1d207e9408 100644 --- a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasUndoManager.h +++ b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasUndoManager.h @@ -61,6 +61,7 @@ namespace ScriptCanvasEditor public: AZ_CLASS_ALLOCATOR(SceneUndoState, AZ::SystemAllocator, 0); + SceneUndoState() = default; SceneUndoState(AzToolsFramework::UndoSystem::IUndoNotify* undoNotify); ~SceneUndoState(); diff --git a/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.cpp b/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.cpp index 06bbd29250..5d415f5fd9 100644 --- a/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.cpp @@ -15,7 +15,7 @@ namespace ScriptCanvasEditor { - AZ::Data::AssetId ReadRecentAssetId() + SourceHandle ReadRecentAssetId() { QSettings settings(QSettings::IniFormat, QSettings::UserScope, SCRIPTCANVASEDITOR_AZ_QCOREAPPLICATION_SETTINGS_ORGANIZATION_NAME); @@ -26,20 +26,15 @@ namespace ScriptCanvasEditor recentOpenFileLocation = settings.value(SCRIPTCANVASEDITOR_SETTINGS_RECENT_OPEN_FILE_LOCATION_KEY).toString(); settings.endGroup(); - if (recentOpenFileLocation.isEmpty()) - { - return {}; - } - AZ::Data::AssetId assetId(recentOpenFileLocation.toUtf8().constData()); - return assetId; + return { nullptr, {}, recentOpenFileLocation.toUtf8().constData() }; } - void SetRecentAssetId(const AZ::Data::AssetId& assetId) + void SetRecentAssetId(SourceHandle assetId) { QSettings settings(QSettings::IniFormat, QSettings::UserScope, SCRIPTCANVASEDITOR_AZ_QCOREAPPLICATION_SETTINGS_ORGANIZATION_NAME); - AZStd::string guidStr = assetId.m_guid.ToString(); + AZStd::string guidStr = assetId.Id().ToString(); settings.beginGroup(SCRIPTCANVASEDITOR_NAME_SHORT); settings.setValue(SCRIPTCANVASEDITOR_SETTINGS_RECENT_OPEN_FILE_LOCATION_KEY, diff --git a/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.h b/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.h index 0aa4332ca4..aaef02ca58 100644 --- a/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.h +++ b/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.h @@ -8,10 +8,11 @@ #pragma once #include +#include namespace ScriptCanvasEditor { - AZ::Data::AssetId ReadRecentAssetId(); - void SetRecentAssetId(const AZ::Data::AssetId& assetId); + SourceHandle ReadRecentAssetId(); + void SetRecentAssetId(SourceHandle assetId); void ClearRecentAssetId(); } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/AssetGraphSceneDataBus.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/AssetGraphSceneDataBus.h index cbb8ef12d6..6d2c3280ac 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/AssetGraphSceneDataBus.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/AssetGraphSceneDataBus.h @@ -11,14 +11,16 @@ #include #include #include +#include namespace ScriptCanvasEditor { + // #sc-editor-asset remove this class AssetGraphScene : public AZ::EBusTraits { public: - virtual AZ::EntityId FindEditorNodeIdByAssetNodeId(const AZ::Data::AssetId& assetId, AZ::EntityId assetNodeId) const = 0; - virtual AZ::EntityId FindAssetNodeIdByEditorNodeId(const AZ::Data::AssetId& assetId, AZ::EntityId editorNodeId) const = 0; + virtual AZ::EntityId FindEditorNodeIdByAssetNodeId(const SourceHandle& assetId, AZ::EntityId assetNodeId) const = 0; + virtual AZ::EntityId FindAssetNodeIdByEditorNodeId(const SourceHandle& assetId, AZ::EntityId editorNodeId) const = 0; }; using AssetGraphSceneBus = AZ::EBus; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp index dfa39b0047..69fe4053fe 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp @@ -36,7 +36,7 @@ namespace ScriptCanvasEditor { namespace Widget { - CanvasWidget::CanvasWidget(const AZ::Data::AssetId& assetId, QWidget* parent) + CanvasWidget::CanvasWidget(const ScriptCanvasEditor::SourceHandle& assetId, QWidget* parent) : QWidget(parent) , ui(new Ui::CanvasWidget()) , m_attached(false) @@ -69,25 +69,15 @@ namespace ScriptCanvasEditor void CanvasWidget::ShowScene(const ScriptCanvas::ScriptCanvasId& scriptCanvasId) { EditorGraphRequests* editorGraphRequests = EditorGraphRequestBus::FindFirstHandler(scriptCanvasId); - - editorGraphRequests->SetAssetId(m_assetId); editorGraphRequests->CreateGraphCanvasScene(); - AZ::EntityId graphCanvasSceneId = editorGraphRequests->GetGraphCanvasGraphId(); - m_graphicsView->SetScene(graphCanvasSceneId); - m_scriptCanvasId = scriptCanvasId; } - void CanvasWidget::SetAssetId(const AZ::Data::AssetId& assetId) + void CanvasWidget::SetAssetId(const ScriptCanvasEditor::SourceHandle& assetId) { m_assetId = assetId; - - if (EditorGraphRequests* editorGraphRequests = EditorGraphRequestBus::FindFirstHandler(m_scriptCanvasId)) - { - editorGraphRequests->SetAssetId(m_assetId); - } } const GraphCanvas::ViewId& CanvasWidget::GetViewId() const diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.h index 9abb41aacc..fc04486c36 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.h @@ -21,6 +21,7 @@ AZ_POP_DISABLE_WARNING #include #include +#include #endif class QVBoxLayout; @@ -46,13 +47,13 @@ namespace ScriptCanvasEditor Q_OBJECT public: AZ_CLASS_ALLOCATOR(CanvasWidget, AZ::SystemAllocator, 0); - CanvasWidget(const AZ::Data::AssetId& assetId, QWidget* parent = nullptr); + CanvasWidget(const ScriptCanvasEditor::SourceHandle& assetId, QWidget* parent = nullptr); ~CanvasWidget() override; void SetDefaultBorderColor(AZ::Color defaultBorderColor); void ShowScene(const ScriptCanvas::ScriptCanvasId& scriptCanvasId); - void SetAssetId(const AZ::Data::AssetId& assetId); + void SetAssetId(const ScriptCanvasEditor::SourceHandle& assetId); const GraphCanvas::ViewId& GetViewId() const; @@ -69,7 +70,7 @@ namespace ScriptCanvasEditor void SetupGraphicsView(); - AZ::Data::AssetId m_assetId; + ScriptCanvasEditor::SourceHandle m_assetId; AZStd::unique_ptr ui; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp index f2963287c6..4e9398fdcf 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp @@ -23,6 +23,8 @@ #include +#include + namespace ScriptCanvasEditor { namespace Widget @@ -31,7 +33,7 @@ namespace ScriptCanvasEditor // GraphTabBar //////////////// - GraphTabBar::GraphTabBar(QWidget* parent /*= nullptr*/) + GraphTabBar::GraphTabBar(QWidget* parent) : AzQtComponents::TabBar(parent) { setTabsClosable(true); @@ -44,49 +46,128 @@ namespace ScriptCanvasEditor connect(this, &QTabBar::customContextMenuRequested, this, &GraphTabBar::OnContextMenu); } - void GraphTabBar::AddGraphTab(const AZ::Data::AssetId& assetId) + void GraphTabBar::AddGraphTab(ScriptCanvasEditor::SourceHandle assetId, Tracker::ScriptCanvasFileState fileState) { - InsertGraphTab(count(), assetId); + InsertGraphTab(count(), assetId, fileState); } - int GraphTabBar::InsertGraphTab(int tabIndex, const AZ::Data::AssetId& assetId) + void GraphTabBar::ClearTabView(int tabIndex) + { + if (tabIndex < count()) + { + if (QVariant tabDataVariant = tabData(tabIndex); tabDataVariant.isValid()) + { + GraphTabMetadata replacement = tabDataVariant.value(); + if (replacement.m_canvasWidget) + { + delete replacement.m_canvasWidget; + replacement.m_canvasWidget = nullptr; + tabDataVariant.setValue(replacement); + setTabData(tabIndex, tabDataVariant); + } + } + } + } + + CanvasWidget* GraphTabBar::ModOrCreateTabView(int tabIndex) + { + if (tabIndex < count()) + { + if (QVariant tabDataVariant = tabData(tabIndex); tabDataVariant.isValid()) + { + if (!tabDataVariant.value().m_canvasWidget) + { + CanvasWidget* canvasWidget = new CanvasWidget(tabDataVariant.value().m_assetId, this); + canvasWidget->SetDefaultBorderColor(ScriptCanvasAssetDescription().GetDisplayColorImpl()); + GraphTabMetadata replacement = tabDataVariant.value(); + replacement.m_canvasWidget = canvasWidget; + tabDataVariant.setValue(replacement); + setTabData(tabIndex, tabDataVariant); + } + + return tabDataVariant.value().m_canvasWidget; + } + } + + return nullptr; + } + + CanvasWidget* GraphTabBar::ModTabView(int tabIndex) + { + if (tabIndex < count()) + { + if (QVariant tabDataVariant = tabData(tabIndex); tabDataVariant.isValid()) + { + return tabDataVariant.value().m_canvasWidget; + } + } + + return nullptr; + } + + AZStd::optional GraphTabBar::GetTabData(int tabIndex) const + { + if (tabIndex < count()) + { + if (QVariant tabDataVariant = tabData(tabIndex); tabDataVariant.isValid()) + { + return tabDataVariant.value(); + } + } + + return AZStd::nullopt; + } + + AZStd::optional GraphTabBar::GetTabData(ScriptCanvasEditor::SourceHandle assetId) const + { + return GetTabData(FindTab(assetId)); + } + + void GraphTabBar::SetTabData(const GraphTabMetadata& metadata, int tabIndex) + { + if (tabIndex < count()) + { + setTabData(tabIndex, QVariant::fromValue(metadata)); + } + } + + void GraphTabBar::SetTabData(const GraphTabMetadata& metadata, ScriptCanvasEditor::SourceHandle assetId) + { + auto index = FindTab(assetId); + auto replacement = GetTabData(assetId); + + if (index >= 0 && replacement) + { + replacement->m_assetId = assetId; + SetTabData(metadata, index); + } + } + + int GraphTabBar::InsertGraphTab(int tabIndex, ScriptCanvasEditor::SourceHandle assetId, Tracker::ScriptCanvasFileState fileState) { if (!SelectTab(assetId)) { - AZStd::shared_ptr memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); + QIcon tabIcon = QIcon(ScriptCanvasAssetDescription().GetIconPathImpl()); + tabIndex = qobject_cast(parent())->insertTab(tabIndex, new QWidget(), tabIcon, ""); + GraphTabMetadata metaData; + CanvasWidget* canvasWidget = new CanvasWidget(assetId, this); + canvasWidget->SetDefaultBorderColor(ScriptCanvasAssetDescription().GetDisplayColorImpl()); + metaData.m_canvasWidget = canvasWidget; + metaData.m_assetId = assetId; + metaData.m_fileState = fileState; + + AZStd::string tabName; + AzFramework::StringFunc::Path::GetFileName(assetId.Path().c_str(), tabName); - if (memoryAsset) - { - ScriptCanvas::AssetDescription assetDescription = memoryAsset->GetAsset().Get()->GetAssetDescription(); - - QIcon tabIcon = QIcon(assetDescription.GetIconPathImpl()); - int newTabIndex = qobject_cast(parent())->insertTab(tabIndex, new QWidget(), tabIcon, ""); - - CanvasWidget* canvasWidget = memoryAsset->CreateView(this); - - canvasWidget->SetDefaultBorderColor(assetDescription.GetDisplayColorImpl()); - - AZStd::string tabName; - AzFramework::StringFunc::Path::GetFileName(memoryAsset->GetAbsolutePath().c_str(), tabName); - - ConfigureTab(newTabIndex, assetId, tabName); - - // new graphs will need to use their in-memory assetid which we'll need to update - // upon saving the asset - if (!memoryAsset->GetFileAssetId().IsValid()) - { - setTabData(newTabIndex, QVariant::fromValue(memoryAsset->GetId())); - } - - return newTabIndex; - } + SetTabText(tabIndex, tabName.c_str(), fileState); + setTabData(tabIndex, QVariant::fromValue(metaData)); + return tabIndex; } return -1; } - bool GraphTabBar::SelectTab(const AZ::Data::AssetId& assetId) + bool GraphTabBar::SelectTab(ScriptCanvasEditor::SourceHandle assetId) { int tabIndex = FindTab(assetId); if (-1 != tabIndex) @@ -94,74 +175,119 @@ namespace ScriptCanvasEditor setCurrentIndex(tabIndex); return true; } + return false; } - void GraphTabBar::ConfigureTab(int tabIndex, AZ::Data::AssetId fileAssetId, const AZStd::string& tabName) - { - if (fileAssetId.IsValid()) - { - QVariant tabDataVariant = tabData(tabIndex); - - if (tabDataVariant.isValid()) - { - auto tabAssetId = tabDataVariant.value(); - MemoryAssetNotificationBus::MultiHandler::BusDisconnect(tabAssetId); - } - - setTabData(tabIndex, QVariant::fromValue(fileAssetId)); - - MemoryAssetNotificationBus::MultiHandler::BusConnect(fileAssetId); - } - - Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::INVALID; - AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, fileAssetId); - - SetTabText(tabIndex, tabName.c_str(), fileState); - } - - int GraphTabBar::FindTab(const AZ::Data::AssetId& assetId) const + int GraphTabBar::FindTab(ScriptCanvasEditor::SourceHandle assetId) const { for (int tabIndex = 0; tabIndex < count(); ++tabIndex) { QVariant tabDataVariant = tabData(tabIndex); if (tabDataVariant.isValid()) { - auto tabAssetId = tabDataVariant.value(); - if (tabAssetId == assetId) + auto tabAssetId = tabDataVariant.value(); + if (tabAssetId.m_assetId.AnyEquals(assetId)) { return tabIndex; } } } + return -1; } - AZ::Data::AssetId GraphTabBar::FindAssetId(int tabIndex) + int GraphTabBar::FindTab(ScriptCanvasEditor::GraphPtrConst graph) const + { + for (int tabIndex = 0; tabIndex < count(); ++tabIndex) + { + QVariant tabDataVariant = tabData(tabIndex); + if (tabDataVariant.isValid()) + { + auto tabAssetId = tabDataVariant.value(); + if (tabAssetId.m_assetId.Get() == graph) + { + return tabIndex; + } + } + } + + return -1; + } + + int GraphTabBar::FindSaveOverMatch(ScriptCanvasEditor::SourceHandle assetId) const + { + for (int tabIndex = 0; tabIndex < count(); ++tabIndex) + { + QVariant tabDataVariant = tabData(tabIndex); + if (tabDataVariant.isValid()) + { + auto tabAssetId = tabDataVariant.value(); + if (tabAssetId.m_assetId.Get() != assetId.Get() && tabAssetId.m_assetId.PathEquals(assetId)) + { + return tabIndex; + } + } + } + + return -1; + } + + ScriptCanvasEditor::SourceHandle GraphTabBar::FindTabByPath(AZStd::string_view path) const + { + ScriptCanvasEditor::SourceHandle candidate(nullptr, {}, path); + + for (int index = 0; index < count(); ++index) + { + QVariant tabdata = tabData(index); + if (tabdata.isValid()) + { + auto tabAssetId = tabdata.value(); + if (tabAssetId.m_assetId.AnyEquals(candidate)) + { + return tabAssetId.m_assetId; + } + } + } + + return {}; + } + + ScriptCanvasEditor::SourceHandle GraphTabBar::FindAssetId(int tabIndex) { QVariant dataVariant = tabData(tabIndex); if (dataVariant.isValid()) { - auto tabAssetId = dataVariant.value(); - return tabAssetId; + auto tabAssetId = dataVariant.value(); + return tabAssetId.m_assetId; } - return AZ::Data::AssetId(); + return ScriptCanvasEditor::SourceHandle(); + } + + ScriptCanvas::ScriptCanvasId GraphTabBar::FindScriptCanvasIdFromGraphCanvasId(const GraphCanvas::GraphId& graphCanvasGraphId) const + { + for (int index = 0; index < count(); ++index) + { + QVariant tabdata = tabData(index); + if (tabdata.isValid()) + { + auto tabAssetId = tabdata.value(); + if (tabAssetId.m_assetId.IsGraphValid() + && tabAssetId.m_assetId.Get()->GetGraphCanvasGraphId() == graphCanvasGraphId) + { + return tabAssetId.m_assetId.Get()->GetScriptCanvasId(); + } + } + } + + return ScriptCanvas::ScriptCanvasId{}; } void GraphTabBar::CloseTab(int index) { if (index >= 0 && index < count()) { - QVariant tabdata = tabData(index); - if (tabdata.isValid()) - { - auto tabAssetId = tabdata.value(); - - MemoryAssetNotificationBus::MultiHandler::BusDisconnect(tabAssetId); - AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::ClearView, tabAssetId); - } - qobject_cast(parent())->removeTab(index); } } @@ -172,8 +298,6 @@ namespace ScriptCanvasEditor { Q_EMIT TabCloseNoButton(i); } - - MemoryAssetNotificationBus::MultiHandler::BusDisconnect(); } void GraphTabBar::OnContextMenu(const QPoint& point) @@ -187,11 +311,9 @@ namespace ScriptCanvasEditor QVariant tabdata = tabData(tabIndex); if (tabdata.isValid()) { - auto tabAssetId = tabdata.value(); - - Tracker::ScriptCanvasFileState fileState; - AssetTrackerRequestBus::BroadcastResult(fileState , &AssetTrackerRequests::GetFileState, tabAssetId); + auto tabAssetId = tabdata.value(); + Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::INVALID; isModified = fileState == Tracker::ScriptCanvasFileState::NEW || fileState == Tracker::ScriptCanvasFileState::MODIFIED; } @@ -263,23 +385,14 @@ namespace ScriptCanvasEditor AzQtComponents::TabBar::mouseReleaseEvent(event); } - void GraphTabBar::OnFileStateChanged(Tracker::ScriptCanvasFileState fileState) - { - const AZ::Data::AssetId* fileAssetId = MemoryAssetNotificationBus::GetCurrentBusId(); - - if (fileAssetId) - { - SetFileState((*fileAssetId), fileState); - - if (FindTab((*fileAssetId)) == currentIndex()) - { - Q_EMIT OnActiveFileStateChanged(); - } - } - } - void GraphTabBar::SetTabText(int tabIndex, const QString& path, Tracker::ScriptCanvasFileState fileState) { + QString safePath = path; + if (path.endsWith("^") || path.endsWith("*")) + { + safePath.chop(1); + } + if (tabIndex >= 0 && tabIndex < count()) { const char* fileStateTag = ""; @@ -296,7 +409,7 @@ namespace ScriptCanvasEditor break; } - setTabText(tabIndex, QString("%1%2").arg(path).arg(fileStateTag)); + setTabText(tabIndex, QString("%1%2").arg(safePath).arg(fileStateTag)); } } @@ -314,6 +427,23 @@ namespace ScriptCanvasEditor Q_EMIT TabRemoved(index); } + void GraphTabBar::UpdateFileState(const ScriptCanvasEditor::SourceHandle& assetId, Tracker::ScriptCanvasFileState fileState) + { + auto tabData = GetTabData(assetId); + if (tabData && tabData->m_fileState != fileState) + { + int index = FindTab(assetId); + tabData->m_fileState = fileState; + SetTabData(*tabData, assetId); + SetTabText(index, tabText(index), fileState); + + if (index == currentIndex()) + { + Q_EMIT OnActiveFileStateChanged(); + } + } + } + void GraphTabBar::currentChangedTab(int index) { if (index < 0) @@ -327,7 +457,7 @@ namespace ScriptCanvasEditor return; } - auto assetId = tabdata.value(); + auto assetId = tabdata.value().m_assetId; ScriptCanvasEditor::GeneralRequestBus::Broadcast(&ScriptCanvasEditor::GeneralRequests::OnChangeActiveGraphTab, assetId); @@ -338,24 +468,6 @@ namespace ScriptCanvasEditor } } - void GraphTabBar::SetFileState(AZ::Data::AssetId assetId, Tracker::ScriptCanvasFileState fileState) - { - int index = FindTab(assetId); - - if (index >= 0 && index < count()) - { - QVariant tabdata = tabData(index); - if (tabdata.isValid()) - { - auto tabAssetId = tabdata.value(); - - AZStd::string tabName; - AssetTrackerRequestBus::BroadcastResult(tabName, &AssetTrackerRequests::GetTabName, tabAssetId); - SetTabText(index, tabName.c_str(), fileState); - } - } - } - #include } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h index 47a5cb8651..939fb7c8f4 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h @@ -16,7 +16,10 @@ #include #include +#include #include +#include + #endif class QGraphicsView; @@ -26,17 +29,18 @@ namespace ScriptCanvasEditor { namespace Widget { + class CanvasWidget; + struct GraphTabMetadata { - AZ::Data::AssetId m_assetId; + SourceHandle m_assetId; QWidget* m_hostWidget = nullptr; - QString m_tabName; + CanvasWidget* m_canvasWidget = nullptr; Tracker::ScriptCanvasFileState m_fileState = Tracker::ScriptCanvasFileState::INVALID; }; class GraphTabBar : public AzQtComponents::TabBar - , public MemoryAssetNotificationBus::MultiHandler { Q_OBJECT @@ -45,30 +49,39 @@ namespace ScriptCanvasEditor GraphTabBar(QWidget* parent = nullptr); ~GraphTabBar() override = default; - void AddGraphTab(const AZ::Data::AssetId& assetId); - int InsertGraphTab(int tabIndex, const AZ::Data::AssetId& assetId); - bool SelectTab(const AZ::Data::AssetId& assetId); - - void ConfigureTab(int tabIndex, AZ::Data::AssetId fileAssetId, const AZStd::string& tabName); - - int FindTab(const AZ::Data::AssetId& assetId) const; - AZ::Data::AssetId FindAssetId(int tabIndex); + AZStd::optional GetTabData(int index) const; + AZStd::optional GetTabData(ScriptCanvasEditor::SourceHandle assetId) const; + void SetTabData(const GraphTabMetadata& data, int index); + void SetTabData(const GraphTabMetadata& data, ScriptCanvasEditor::SourceHandle assetId); + void AddGraphTab(ScriptCanvasEditor::SourceHandle assetId, Tracker::ScriptCanvasFileState fileState); void CloseTab(int index); void CloseAllTabs(); + int InsertGraphTab(int tabIndex, ScriptCanvasEditor::SourceHandle assetId, Tracker::ScriptCanvasFileState fileState); + bool SelectTab(ScriptCanvasEditor::SourceHandle assetId); + + int FindTab(ScriptCanvasEditor::SourceHandle assetId) const; + int FindTab(ScriptCanvasEditor::GraphPtrConst graph) const; + int FindSaveOverMatch(ScriptCanvasEditor::SourceHandle assetId) const; + ScriptCanvasEditor::SourceHandle FindTabByPath(AZStd::string_view path) const; + ScriptCanvasEditor::SourceHandle FindAssetId(int tabIndex); + ScriptCanvas::ScriptCanvasId FindScriptCanvasIdFromGraphCanvasId(const GraphCanvas::GraphId& graphCanvasGraphId) const; + + void ClearTabView(int tabIndex); + CanvasWidget* ModOrCreateTabView(int tabIndex); + CanvasWidget* ModTabView(int tabIndex); + void OnContextMenu(const QPoint& point); void mouseReleaseEvent(QMouseEvent* event) override; - // MemoryAssetNotifications - void OnFileStateChanged(Tracker::ScriptCanvasFileState fileState) override; - //// - // Updates the tab at the supplied index with the GraphTabMetadata // The host widget field of the tabMetadata is not used and will not overwrite the tab data void SetTabText(int tabIndex, const QString& path, Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::INVALID); + void UpdateFileState(const ScriptCanvasEditor::SourceHandle& assetId, Tracker::ScriptCanvasFileState fileState); + Q_SIGNALS: void TabInserted(int index); void TabRemoved(int index); @@ -92,8 +105,6 @@ namespace ScriptCanvasEditor // Called when the selected tab changes void currentChangedTab(int index); - void SetFileState(AZ::Data::AssetId assetId, Tracker::ScriptCanvasFileState fileState); - int m_signalSaveOnChangeTo = -1; }; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowSession.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowSession.cpp index 5fadb0a81e..963be52edc 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowSession.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowSession.cpp @@ -256,7 +256,8 @@ namespace ScriptCanvasEditor const AZ::Data::AssetId& assetId = executionItem->GetAssetId(); - GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId, assetId); + GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId + , SourceHandle(nullptr, assetId.m_guid, {}), Tracker::ScriptCanvasFileState::UNMODIFIED); } } } @@ -270,12 +271,14 @@ namespace ScriptCanvasEditor const AZ::Data::AssetId& assetId = executionItem->GetAssetId(); bool isAssetOpen = false; - GeneralRequestBus::BroadcastResult(isAssetOpen, &GeneralRequests::IsScriptCanvasAssetOpen, assetId); + GeneralRequestBus::BroadcastResult(isAssetOpen, &GeneralRequests::IsScriptCanvasAssetOpen, SourceHandle(nullptr, assetId.m_guid, {})); - GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId, assetId); + GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId + , SourceHandle(nullptr, assetId.m_guid, {}), Tracker::ScriptCanvasFileState::UNMODIFIED); AZ::EntityId graphCanvasGraphId; - GeneralRequestBus::BroadcastResult(graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, assetId); + GeneralRequestBus::BroadcastResult(graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId + , SourceHandle(nullptr, assetId.m_guid, {})); if (isAssetOpen) { @@ -348,7 +351,7 @@ namespace ScriptCanvasEditor GeneralRequestBus::BroadcastResult(activeGraphCanvasGraphId, &GeneralRequests::GetActiveGraphCanvasGraphId); AZ::EntityId graphCanvasGraphId; - GeneralRequestBus::BroadcastResult(graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, m_assetId); + GeneralRequestBus::BroadcastResult(graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, SourceHandle(nullptr, m_assetId.m_guid, {})); if (activeGraphCanvasGraphId == graphCanvasGraphId) { @@ -366,7 +369,7 @@ namespace ScriptCanvasEditor GraphCanvas::FocusConfig focusConfig; AZ::EntityId scriptCanvasNodeId; - AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, assetId, assetNodeId); + AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, SourceHandle(nullptr, assetId.m_guid, {}), assetNodeId); GraphCanvas::NodeId graphCanvasNodeId; SceneMemberMappingRequestBus::EventResult(graphCanvasNodeId, scriptCanvasNodeId, &SceneMemberMappingRequests::GetGraphCanvasEntityId); @@ -403,12 +406,12 @@ namespace ScriptCanvasEditor void LoggingWindowSession::HighlightElement(const AZ::Data::AssetId& assetId, const AZ::EntityId& assetNodeId) { AZ::EntityId graphCanvasGraphId; - GeneralRequestBus::BroadcastResult(graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, assetId); + GeneralRequestBus::BroadcastResult(graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, SourceHandle(nullptr, assetId.m_guid, {})); if (graphCanvasGraphId.IsValid()) { AZ::EntityId scriptCanvasNodeId; - AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, assetId, assetNodeId); + AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, SourceHandle(nullptr, assetId.m_guid, {}), assetNodeId); GraphCanvas::NodeId graphCanvasNodeId; SceneMemberMappingRequestBus::EventResult(graphCanvasNodeId, scriptCanvasNodeId, &SceneMemberMappingRequests::GetGraphCanvasEntityId); @@ -447,7 +450,7 @@ namespace ScriptCanvasEditor if (effectIter != m_highlightEffects.end()) { AZ::EntityId graphCanvasGraphId; - GeneralRequestBus::BroadcastResult(graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, assetId); + GeneralRequestBus::BroadcastResult(graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, SourceHandle(nullptr, assetId.m_guid, {})); if (graphCanvasGraphId.IsValid()) { diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp index b992d3a289..6936a0c368 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp @@ -122,7 +122,11 @@ namespace ScriptCanvasEditor { } - ExecutionLogTreeItem* DebugLogRootItem::CreateExecutionItem(const LoggingDataId& loggingDataId, const ScriptCanvas::NodeTypeIdentifier& nodeType, const ScriptCanvas::GraphInfo& graphInfo, const ScriptCanvas::NamedNodeId& nodeId) + ExecutionLogTreeItem* DebugLogRootItem::CreateExecutionItem + ( [[maybe_unused]] const LoggingDataId& loggingDataId + , [[maybe_unused]] const ScriptCanvas::NodeTypeIdentifier& nodeType + , [[maybe_unused]] const ScriptCanvas::GraphInfo& graphInfo + , [[maybe_unused]] const ScriptCanvas::NamedNodeId& nodeId) { ExecutionLogTreeItem* treeItem = nullptr; @@ -133,15 +137,6 @@ namespace ScriptCanvasEditor m_additionTimer.start(); } } - - if (m_updatePolicy == UpdatePolicy::SingleTime) - { - treeItem = CreateChildNodeWithoutAddSignal(loggingDataId, nodeType, graphInfo, nodeId); - } - else - { - treeItem = CreateChildNode(loggingDataId, nodeType, graphInfo, nodeId); - } return treeItem; } @@ -185,7 +180,11 @@ namespace ScriptCanvasEditor // ExecutionLogTreeItem ///////////////////////// - ExecutionLogTreeItem::ExecutionLogTreeItem(const LoggingDataId& loggingDataId, const ScriptCanvas::NodeTypeIdentifier& nodeType, const ScriptCanvas::GraphInfo& graphInfo, const ScriptCanvas::NamedNodeId& nodeId) + ExecutionLogTreeItem::ExecutionLogTreeItem + ( const LoggingDataId& loggingDataId + , const ScriptCanvas::NodeTypeIdentifier& nodeType + , const SourceHandle& graphInfo + , const ScriptCanvas::NamedNodeId& nodeId) : m_loggingDataId(loggingDataId) , m_nodeType(nodeType) , m_graphInfo(graphInfo) @@ -196,7 +195,6 @@ namespace ScriptCanvasEditor m_paletteConfiguration.SetColorPalette("MethodNodeTitlePalette"); AZ::NamedEntityId entityName; - LoggingDataRequestBus::EventResult(entityName, m_loggingDataId, &LoggingDataRequests::FindNamedEntityId, m_graphInfo.m_runtimeEntity); m_sourceEntityName = entityName.ToString().c_str(); m_displayName = nodeId.m_name.c_str(); @@ -207,7 +205,7 @@ namespace ScriptCanvasEditor m_inputName = "---"; m_outputName = "---"; - GeneralAssetNotificationBus::Handler::BusConnect(GetAssetId()); + GeneralAssetNotificationBus::Handler::BusConnect(graphInfo); } QVariant ExecutionLogTreeItem::Data(const QModelIndex& index, int role) const @@ -502,12 +500,12 @@ namespace ScriptCanvasEditor const ScriptCanvas::GraphIdentifier& ExecutionLogTreeItem::GetGraphIdentifier() const { - return m_graphInfo.m_graphIdentifier; + return m_graphIdentifier; } - const AZ::Data::AssetId& ExecutionLogTreeItem::GetAssetId() const + AZ::Data::AssetId ExecutionLogTreeItem::GetAssetId() const { - return m_graphInfo.m_graphIdentifier.m_assetId; + return m_graphInfo.Id(); } AZ::EntityId ExecutionLogTreeItem::GetScriptCanvasAssetNodeId() const @@ -623,12 +621,14 @@ namespace ScriptCanvasEditor { if (!m_graphCanvasGraphId.IsValid()) { - GeneralRequestBus::BroadcastResult(m_graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, GetAssetId()); + GeneralRequestBus::BroadcastResult(m_graphCanvasGraphId + , &GeneralRequests::FindGraphCanvasGraphIdByAssetId, SourceHandle(nullptr, GetAssetId().m_guid, "")); if (!EditorGraphNotificationBus::Handler::BusIsConnected()) { ScriptCanvas::ScriptCanvasId scriptCanvasId; - GeneralRequestBus::BroadcastResult(scriptCanvasId, &GeneralRequests::FindScriptCanvasIdByAssetId, GetAssetId()); + GeneralRequestBus::BroadcastResult(scriptCanvasId + , &GeneralRequests::FindScriptCanvasIdByAssetId, SourceHandle(nullptr, GetAssetId().m_guid, "")); EditorGraphNotificationBus::Handler::BusConnect(scriptCanvasId); } @@ -638,7 +638,9 @@ namespace ScriptCanvasEditor { if (!m_graphCanvasNodeId.IsValid()) { - AssetGraphSceneBus::BroadcastResult(m_scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, GetAssetId(), m_scriptCanvasAssetNodeId); + AssetGraphSceneBus::BroadcastResult(m_scriptCanvasNodeId + , &AssetGraphScene::FindEditorNodeIdByAssetNodeId + , SourceHandle(nullptr, GetAssetId().m_guid, ""), m_scriptCanvasAssetNodeId); SceneMemberMappingRequestBus::EventResult(m_graphCanvasNodeId, m_scriptCanvasNodeId, &SceneMemberMappingRequests::GetGraphCanvasEntityId); } @@ -806,7 +808,8 @@ namespace ScriptCanvasEditor { if (!m_graphCanvasGraphId.IsValid()) { - GeneralRequestBus::BroadcastResult(m_graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, m_graphIdentifier.m_assetId); + GeneralRequestBus::BroadcastResult(m_graphCanvasGraphId + , &GeneralRequests::FindGraphCanvasGraphIdByAssetId, SourceHandle(nullptr, m_graphIdentifier.m_assetId.m_guid, "")); } ScrapeInputName(); @@ -828,7 +831,7 @@ namespace ScriptCanvasEditor if (m_graphCanvasGraphId.IsValid() && m_assetInputEndpoint.IsValid()) { AZ::EntityId scriptCanvasNodeId; - AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, GetAssetId(), m_assetInputEndpoint.GetNodeId()); + AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, SourceHandle(nullptr, GetAssetId().m_guid, ""), m_assetInputEndpoint.GetNodeId()); GraphCanvas::NodeId graphCanvasNodeId; SceneMemberMappingRequestBus::EventResult(graphCanvasNodeId, scriptCanvasNodeId, &SceneMemberMappingRequests::GetGraphCanvasEntityId); @@ -851,8 +854,9 @@ namespace ScriptCanvasEditor if (m_graphCanvasGraphId.IsValid() && m_assetOutputEndpoint.IsValid()) { AZ::EntityId scriptCanvasNodeId; - AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, GetAssetId(), m_assetOutputEndpoint.GetNodeId()); - + AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId + , SourceHandle(nullptr, GetAssetId().m_guid, ""), m_assetOutputEndpoint.GetNodeId()); + GraphCanvas::NodeId graphCanvasNodeId; SceneMemberMappingRequestBus::EventResult(graphCanvasNodeId, scriptCanvasNodeId, &SceneMemberMappingRequests::GetGraphCanvasEntityId); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.h index 862b231f3a..5b6d23590b 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.h @@ -131,7 +131,12 @@ namespace ScriptCanvasEditor AZ_CLASS_ALLOCATOR(ExecutionLogTreeItem, AZ::SystemAllocator, 0); AZ_RTTI(ExecutionLogTreeItem, "{71139142-A30C-4A16-81CC-D51314AEAF7D}", DebugLogTreeItem); - ExecutionLogTreeItem(const LoggingDataId& loggingDataId, const ScriptCanvas::NodeTypeIdentifier& nodeType, const ScriptCanvas::GraphInfo& graphInfo, const ScriptCanvas::NamedNodeId& nodeId); + ExecutionLogTreeItem + ( const LoggingDataId& loggingDataId + , const ScriptCanvas::NodeTypeIdentifier& nodeType + , const SourceHandle& graphInfo + , const ScriptCanvas::NamedNodeId& nodeId); + ~ExecutionLogTreeItem() override = default; QVariant Data(const QModelIndex& index, int role) const override final; @@ -163,7 +168,7 @@ namespace ScriptCanvasEditor //// const ScriptCanvas::GraphIdentifier& GetGraphIdentifier() const; - const AZ::Data::AssetId& GetAssetId() const; + AZ::Data::AssetId GetAssetId() const; AZ::EntityId GetScriptCanvasAssetNodeId() const; GraphCanvas::NodeId GetGraphCanvasNodeId() const; @@ -184,7 +189,8 @@ namespace ScriptCanvasEditor LoggingDataId m_loggingDataId; ScriptCanvas::NodeTypeIdentifier m_nodeType; - ScriptCanvas::GraphInfo m_graphInfo; + SourceHandle m_graphInfo; + ScriptCanvas::GraphIdentifier m_graphIdentifier; QString m_sourceEntityName; QString m_graphName; QString m_relativeGraphPath; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/PivotTree/PivotTreeWidget.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/PivotTree/PivotTreeWidget.cpp index a34b42bed8..b1827d7099 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/PivotTree/PivotTreeWidget.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/PivotTree/PivotTreeWidget.cpp @@ -406,15 +406,14 @@ namespace ScriptCanvasEditor sourceIndex = proxyModel->mapToSource(modelIndex); } - PivotTreeItem* pivotTreeItem = static_cast(sourceIndex.internalPointer()); - - if (pivotTreeItem) + if (PivotTreeItem* pivotTreeItem = static_cast(sourceIndex.internalPointer())) { - PivotTreeGraphItem* graphItem = azrtti_cast(pivotTreeItem); - - if (graphItem) + if (PivotTreeGraphItem* graphItem = azrtti_cast(pivotTreeItem)) { - GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId, graphItem->GetAssetId()); + GeneralRequestBus::Broadcast + ( &GeneralRequests::OpenScriptCanvasAssetId + , SourceHandle(nullptr, graphItem->GetAssetId().m_guid, "") + , Tracker::ScriptCanvasFileState::UNMODIFIED); } } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/FunctionNodePaletteTreeItemTypes.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/FunctionNodePaletteTreeItemTypes.cpp index 50a5e8ac1a..b2db9508b1 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/FunctionNodePaletteTreeItemTypes.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/FunctionNodePaletteTreeItemTypes.cpp @@ -129,7 +129,10 @@ namespace ScriptCanvasEditor { if (row == NodePaletteTreeItem::Column::Customization) { - GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAsset, GetSourceAssetId(), -1); + GeneralRequestBus::Broadcast + ( &GeneralRequests::OpenScriptCanvasAssetId + , SourceHandle(nullptr, GetSourceAssetId().m_guid, "") + , Tracker::ScriptCanvasFileState::UNMODIFIED); } } @@ -137,7 +140,10 @@ namespace ScriptCanvasEditor { if (row != NodePaletteTreeItem::Column::Customization) { - GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAsset, GetSourceAssetId(), -1); + GeneralRequestBus::Broadcast + ( &GeneralRequests::OpenScriptCanvasAssetId + , SourceHandle(nullptr, GetSourceAssetId().m_guid, "") + , Tracker::ScriptCanvasFileState::UNMODIFIED); return true; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp new file mode 100644 index 0000000000..3e4cb7cd49 --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +#include + +#include +#include +#include +#include + +namespace ScriptCanvasEditor +{ + SourceHandlePropertyAssetCtrl::SourceHandlePropertyAssetCtrl(QWidget* parent) + : AzToolsFramework::PropertyAssetCtrl(parent) + { + } + + AzToolsFramework::AssetBrowser::AssetSelectionModel SourceHandlePropertyAssetCtrl::GetAssetSelectionModel() + { + auto selectionModel = AssetSelectionModel::SourceAssetTypeSelection(m_sourceAssetFilterPattern); + selectionModel.SetTitle(m_title); + return selectionModel; + } + + void SourceHandlePropertyAssetCtrl::PopupAssetPicker() + { + // Request the AssetBrowser Dialog and set a type filter + AssetSelectionModel selection = GetAssetSelectionModel(); + selection.SetSelectedFilePath(m_selectedSourcePath.c_str()); + + AZStd::string defaultDirectory; + if (m_defaultDirectoryCallback) + { + m_defaultDirectoryCallback->Invoke(m_editNotifyTarget, defaultDirectory); + selection.SetDefaultDirectory(defaultDirectory); + } + + AssetBrowserComponentRequestBus::Broadcast(&AssetBrowserComponentRequests::PickAssets, selection, parentWidget()); + if (selection.IsValid()) + { + const auto source = azrtti_cast(selection.GetResult()); + AZ_Assert(source, "Incorrect entry type selected. Expected source."); + if (source) + { + SetSelectedSourcePath(source->GetFullPath()); + } + } + } + + void SourceHandlePropertyAssetCtrl::ClearAssetInternal() + { + SetSelectedSourcePath(""); + + PropertyAssetCtrl::ClearAssetInternal(); + } + + void SourceHandlePropertyAssetCtrl::ConfigureAutocompleter() + { + if (m_completerIsConfigured) + { + return; + } + + AzToolsFramework::PropertyAssetCtrl::ConfigureAutocompleter(); + + AssetSelectionModel selection = GetAssetSelectionModel(); + m_model->SetFetchEntryType(AssetBrowserEntry::AssetEntryType::Source); + m_model->SetFilter(selection.GetDisplayFilter()); + } + + void SourceHandlePropertyAssetCtrl::SetSourceAssetFilterPattern(const QString& filterPattern) + { + m_sourceAssetFilterPattern = filterPattern; + } + + AZ::IO::Path SourceHandlePropertyAssetCtrl::GetSelectedSourcePath() const + { + return m_selectedSourcePath; + } + + void SourceHandlePropertyAssetCtrl::SetSelectedSourcePath(const AZ::IO::Path& sourcePath) + { + m_selectedSourcePath = sourcePath; + + AZStd::string displayText; + if (!sourcePath.empty()) + { + AzFramework::StringFunc::Path::GetFileName(sourcePath.c_str(), displayText); + } + m_browseEdit->setText(displayText.c_str()); + + // The AssetID gets ignored, the only important bit is triggering the change for the RequestWrite + emit OnAssetIDChanged(AZ::Data::AssetId()); + } + + void SourceHandlePropertyAssetCtrl::OnAutocomplete(const QModelIndex& index) + { + SetSelectedSourcePath(m_model->GetPathFromIndex(GetSourceIndex(index))); + } + + QWidget* SourceHandlePropertyHandler::CreateGUI(QWidget* pParent) + { + SourceHandlePropertyAssetCtrl* newCtrl = aznew SourceHandlePropertyAssetCtrl(pParent); + connect(newCtrl, &SourceHandlePropertyAssetCtrl::OnAssetIDChanged, this, [newCtrl](AZ::Data::AssetId newAssetID) + { + (void)newAssetID; + AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&AzToolsFramework::PropertyEditorGUIMessages::RequestWrite, newCtrl); + AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&AzToolsFramework::PropertyEditorGUIMessages::OnEditingFinished, newCtrl); + }); + return newCtrl; + } + + void SourceHandlePropertyHandler::ConsumeAttribute(SourceHandlePropertyAssetCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) + { + // Let the AssetPropertyHandlerDefault handle all of the common attributes + AzToolsFramework::AssetPropertyHandlerDefault::ConsumeAttributeInternal(GUI, attrib, attrValue, debugName); + + if (attrib == AZ::Edit::Attributes::SourceAssetFilterPattern) + { + AZStd::string filterPattern; + if (attrValue->Read(filterPattern)) + { + GUI->SetSourceAssetFilterPattern(filterPattern.c_str()); + } + } + } + + void SourceHandlePropertyHandler::WriteGUIValuesIntoProperty(size_t index, SourceHandlePropertyAssetCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) + { + (void)index; + (void)node; + + auto sourceHandle = SourceHandle(nullptr, GUI->GetSelectedSourcePath()); + auto completeSourceHandle = CompleteDescription(sourceHandle); + if (completeSourceHandle) + { + instance = property_t(*CompleteDescription(sourceHandle)); + } + else + { + instance = property_t(); + } + } + + bool SourceHandlePropertyHandler::ReadValuesIntoGUI(size_t index, SourceHandlePropertyAssetCtrl* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) + { + (void)index; + (void)node; + + GUI->blockSignals(true); + + GUI->SetSelectedSourcePath(instance.Path()); + GUI->SetEditNotifyTarget(node->GetParent()->GetInstance(0)); + + GUI->blockSignals(false); + return false; + } +} diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.h new file mode 100644 index 0000000000..f54279e59c --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include + +#include +#endif + +namespace ScriptCanvasEditor +{ + class SourceHandlePropertyAssetCtrl + : public AzToolsFramework::PropertyAssetCtrl + { + Q_OBJECT + + public: + AZ_CLASS_ALLOCATOR(SourceHandlePropertyAssetCtrl, AZ::SystemAllocator, 0); + + SourceHandlePropertyAssetCtrl(QWidget* parent = nullptr); + + AzToolsFramework::AssetBrowser::AssetSelectionModel GetAssetSelectionModel() override; + void PopupAssetPicker() override; + void ClearAssetInternal() override; + void ConfigureAutocompleter() override; + + void SetSourceAssetFilterPattern(const QString& filterPattern); + + AZ::IO::Path GetSelectedSourcePath() const; + void SetSelectedSourcePath(const AZ::IO::Path& sourcePath); + + public Q_SLOTS: + void OnAutocomplete(const QModelIndex& index) override; + + private: + //! A regular expression pattern for filtering by source assets + //! If this is set, the PropertyAssetCtrl will be dealing with source assets + //! instead of a specific asset type + QString m_sourceAssetFilterPattern; + + AZ::IO::Path m_selectedSourcePath; + }; + + class SourceHandlePropertyHandler + : QObject + , public AzToolsFramework::PropertyHandler + { + Q_OBJECT + + public: + AZ_CLASS_ALLOCATOR(SourceHandlePropertyHandler, AZ::SystemAllocator, 0); + + AZ::u32 GetHandlerName(void) const override { return AZ_CRC_CE("SourceHandle"); } + bool IsDefaultHandler() const override { return true; } + QWidget* GetFirstInTabOrder(SourceHandlePropertyAssetCtrl* widget) override { return widget->GetFirstInTabOrder(); } + QWidget* GetLastInTabOrder(SourceHandlePropertyAssetCtrl* widget) override { return widget->GetLastInTabOrder(); } + void UpdateWidgetInternalTabbing(SourceHandlePropertyAssetCtrl* widget) override { widget->UpdateTabOrder(); } + + QWidget* CreateGUI(QWidget* pParent) override; + void ConsumeAttribute(SourceHandlePropertyAssetCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override; + void WriteGUIValuesIntoProperty(size_t index, SourceHandlePropertyAssetCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) override; + bool ReadValuesIntoGUI(size_t index, SourceHandlePropertyAssetCtrl* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) override; + }; +} diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/StatisticsDialog/ScriptCanvasStatisticsDialog.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/StatisticsDialog/ScriptCanvasStatisticsDialog.cpp index ece93955bb..4a0905c17c 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/StatisticsDialog/ScriptCanvasStatisticsDialog.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/StatisticsDialog/ScriptCanvasStatisticsDialog.cpp @@ -257,7 +257,10 @@ namespace ScriptCanvasEditor if (treeItem->GetAssetId().IsValid()) { - GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId, treeItem->GetAssetId()); + GeneralRequestBus::Broadcast + ( &GeneralRequests::OpenScriptCanvasAssetId + , SourceHandle(nullptr, treeItem->GetAssetId().m_guid, "") + , Tracker::ScriptCanvasFileState::UNMODIFIED); } } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/UnitTestPanel/UnitTestDockWidget.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/UnitTestPanel/UnitTestDockWidget.cpp index 6142729bfe..f319a166df 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/UnitTestPanel/UnitTestDockWidget.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/UnitTestPanel/UnitTestDockWidget.cpp @@ -433,7 +433,10 @@ namespace ScriptCanvasEditor AZ::Data::AssetId sourceAssetId(sourceUuid, 0); AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); - GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAssetId, sourceAssetId); + GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAssetId + , ScriptCanvasEditor::SourceHandle(nullptr, sourceUuid, {}) + , Tracker::ScriptCanvasFileState::UNMODIFIED); + if (!openOutcome) { AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data()); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/GraphVariablesTableView.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/GraphVariablesTableView.cpp index 5b78c62bac..1af554dd32 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/GraphVariablesTableView.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/GraphVariablesTableView.cpp @@ -716,10 +716,7 @@ namespace ScriptCanvasEditor void GraphVariablesModel::SetActiveScene(const ScriptCanvas::ScriptCanvasId& scriptCanvasId) { ScriptCanvas::GraphVariableManagerNotificationBus::Handler::BusDisconnect(); - - m_assetType = AZ::Data::AssetType::CreateNull(); - ScriptCanvas::GraphRequestBus::EventResult(m_assetType, scriptCanvasId, &ScriptCanvas::GraphRequests::GetAssetType); - + m_assetType = azrtti_typeid(); m_scriptCanvasId = scriptCanvasId; if (m_scriptCanvasId.IsValid()) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index e61b015aae..d461ad2a31 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -135,6 +135,7 @@ #include #include #include +#include #include @@ -154,6 +155,7 @@ #include #include +#include namespace ScriptCanvasEditor { @@ -235,7 +237,7 @@ namespace ScriptCanvasEditor Widget::GraphTabBar* tabBar = m_mainWindow->m_tabBar; AZStd::vector activeAssets; - AZ::Data::AssetId focusedAssetId = tabBar->FindAssetId(tabBar->currentIndex()); + ScriptCanvasEditor::SourceHandle focusedAssetId = tabBar->FindAssetId(tabBar->currentIndex()); if (m_rememberOpenCanvases) { @@ -243,44 +245,35 @@ namespace ScriptCanvasEditor for (int i = 0; i < tabBar->count(); ++i) { - AZ::Data::AssetId assetId = tabBar->FindAssetId(i); + ScriptCanvasEditor::SourceHandle assetId = tabBar->FindAssetId(i); const Tracker::ScriptCanvasFileState& fileState = m_mainWindow->GetAssetFileState(assetId); if (fileState == Tracker::ScriptCanvasFileState::MODIFIED || fileState == Tracker::ScriptCanvasFileState::UNMODIFIED) { - AZ::Data::AssetId sourceId = GetSourceAssetId(assetId); - if (sourceId.IsValid()) + ScriptCanvasEditor::SourceHandle sourceId = GetSourceAssetId(assetId); + if (sourceId.IsGraphValid()) { EditorSettings::EditorWorkspace::WorkspaceAssetSaveData assetSaveData; assetSaveData.m_assetId = sourceId; - ScriptCanvas::ScriptCanvasId scriptCanvasId = m_mainWindow->FindScriptCanvasIdByAssetId(assetId); - - EditorGraphRequests* editorRequests = EditorGraphRequestBus::FindFirstHandler(scriptCanvasId); - - if (editorRequests) - { - assetSaveData.m_assetType = azrtti_typeid(); - } - activeAssets.push_back(assetSaveData); } } - else if (assetId == focusedAssetId) + else if (assetId.AnyEquals(focusedAssetId)) { - focusedAssetId.SetInvalid(); + focusedAssetId.Clear(); } } // The assetId needs to be the file AssetId to restore the workspace - if (focusedAssetId.IsValid()) + if (focusedAssetId.IsGraphValid()) { focusedAssetId = GetSourceAssetId(focusedAssetId); } // If our currently focused asset won't be restored, just show the first element. - if (!focusedAssetId.IsValid()) + if (!focusedAssetId.IsGraphValid()) { if (!activeAssets.empty()) { @@ -316,7 +309,7 @@ namespace ScriptCanvasEditor if (m_loadingAssets.empty()) { - m_mainWindow->OnWorkspaceRestoreEnd(AZ::Data::AssetId()); + m_mainWindow->OnWorkspaceRestoreEnd(ScriptCanvasEditor::SourceHandle()); } else { @@ -325,86 +318,81 @@ namespace ScriptCanvasEditor m_queuedAssetFocus = workspace->GetFocusedAssetId(); - for (const auto& assetSaveData : workspace->GetActiveAssetData()) + // #sc-asset-editor + //for (const auto& assetSaveData : workspace->GetActiveAssetData()) { - AssetTrackerNotificationBus::MultiHandler::BusConnect(assetSaveData.m_assetId); - - Callbacks::OnAssetReadyCallback onAssetReady = [this, assetSaveData](ScriptCanvasMemoryAsset& asset) - { - // If we get an error callback. Just remove it from out active lists. - if (asset.IsSourceInError()) - { - if (assetSaveData.m_assetId == m_queuedAssetFocus) - { - m_queuedAssetFocus = AZ::Data::AssetId(); - } - - SignalAssetComplete(asset.GetFileAssetId()); - } - }; - - bool loadedFile = true; - AssetTrackerRequestBus::BroadcastResult(loadedFile, &AssetTrackerRequests::Load, assetSaveData.m_assetId, assetSaveData.m_assetType, onAssetReady); - - if (!loadedFile) - { - if (assetSaveData.m_assetId == m_queuedAssetFocus) - { - m_queuedAssetFocus = AZ::Data::AssetId(); - } - - SignalAssetComplete(assetSaveData.m_assetId); - } + // load all the files +// AssetTrackerNotificationBus::MultiHandler::BusConnect(assetSaveData.m_assetId); +// +// Callbacks::OnAssetReadyCallback onAssetReady = [this, assetSaveData](ScriptCanvasMemoryAsset& asset) +// { +// // If we get an error callback. Just remove it from out active lists. +// if (asset.IsSourceInError()) +// { +// if (assetSaveData.m_assetId == m_queuedAssetFocus) +// { +// m_queuedAssetFocus = ScriptCanvasEditor::SourceHandle(); +// } +// +// SignalAssetComplete(asset.GetFileAssetId()); +// } +// }; +// +// bool loadedFile = true; +// AssetTrackerRequestBus::BroadcastResult(loadedFile, &AssetTrackerRequests::Load, assetSaveData.m_assetId, assetSaveData.m_assetType, onAssetReady); +// +// if (!loadedFile) +// { +// if (assetSaveData.m_assetId == m_queuedAssetFocus) +// { +// m_queuedAssetFocus = ScriptCanvasEditor::SourceHandle(); +// } +// +// SignalAssetComplete(assetSaveData.m_assetId); +// } } } else { - m_mainWindow->OnWorkspaceRestoreEnd(AZ::Data::AssetId()); + m_mainWindow->OnWorkspaceRestoreEnd(ScriptCanvasEditor::SourceHandle()); } } } void Workspace::OnAssetReady(const ScriptCanvasMemoryAsset::pointer memoryAsset) { - const AZ::Data::AssetId& fileAssetId = memoryAsset->GetFileAssetId(); - - if (AssetTrackerNotificationBus::MultiHandler::BusIsConnectedId(fileAssetId)) - { - AssetTrackerNotificationBus::MultiHandler::BusDisconnect(fileAssetId); - - m_mainWindow->OpenScriptCanvasAsset(*memoryAsset); - - SignalAssetComplete(fileAssetId); - } + // open the file in the main window +// const ScriptCanvasEditor::SourceHandle& fileAssetId = memoryAsset->GetFileAssetId(); +// +// if (AssetTrackerNotificationBus::MultiHandler::BusIsConnectedId(fileAssetId)) +// { +// AssetTrackerNotificationBus::MultiHandler::BusDisconnect(fileAssetId); +// +// m_mainWindow->OpenScriptCanvasAsset(*memoryAsset); +// +// SignalAssetComplete(fileAssetId); +// } } - void Workspace::SignalAssetComplete(const AZ::Data::AssetId& fileAssetId) + void Workspace::SignalAssetComplete(const ScriptCanvasEditor::SourceHandle& /*fileAssetId*/) { - auto it = AZStd::find(m_loadingAssets.begin(), m_loadingAssets.end(), fileAssetId); - if (it != m_loadingAssets.end()) - { - m_loadingAssets.erase(it); - } - - //! When we are done loading all assets we can safely set the focus to the recorded asset - if (m_loadingAssets.empty()) - { - m_mainWindow->OnWorkspaceRestoreEnd(m_queuedAssetFocus); - m_queuedAssetFocus.SetInvalid(); - } + // When we are done loading all assets we can safely set the focus to the recorded asset +// auto it = AZStd::find(m_loadingAssets.begin(), m_loadingAssets.end(), fileAssetId); +// if (it != m_loadingAssets.end()) +// { +// m_loadingAssets.erase(it); +// } +// +// if (m_loadingAssets.empty()) +// { +// m_mainWindow->OnWorkspaceRestoreEnd(m_queuedAssetFocus); +// m_queuedAssetFocus.SetInvalid(); +// } } - AZ::Data::AssetId Workspace::GetSourceAssetId(const AZ::Data::AssetId& memoryAssetId) const + ScriptCanvasEditor::SourceHandle Workspace::GetSourceAssetId(const ScriptCanvasEditor::SourceHandle& memoryAssetId) const { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, memoryAssetId); - - if (memoryAsset) - { - return memoryAsset->GetFileAssetId(); - } - - return AZ::Data::AssetId(); + return memoryAssetId; } //////////////// @@ -655,9 +643,9 @@ namespace ScriptCanvasEditor QTimer::singleShot(0, [this]() { SetDefaultLayout(); - if (m_activeAssetId.IsValid()) + if (m_activeGraph.IsGraphValid()) { - m_queuedFocusOverride = m_activeAssetId; + m_queuedFocusOverride = m_activeGraph; } m_workspace->Restore(); @@ -676,8 +664,9 @@ namespace ScriptCanvasEditor ScriptCanvas::BatchOperationNotificationBus::Handler::BusConnect(); AssetGraphSceneBus::Handler::BusConnect(); AzToolsFramework::ToolsApplicationNotificationBus::Handler::BusConnect(); - + AzToolsFramework::AssetSystemBus::Handler::BusConnect(); ScriptCanvas::ScriptCanvasSettingsRequestBus::Handler::BusConnect(); + AZ::SystemTickBus::Handler::BusConnect(); UINotificationBus::Broadcast(&UINotifications::MainWindowCreationEvent, this); @@ -720,6 +709,7 @@ namespace ScriptCanvasEditor ScriptCanvasEditor::GeneralRequestBus::Handler::BusDisconnect(); GraphCanvas::AssetEditorAutomationRequestBus::Handler::BusDisconnect(); ScriptCanvas::ScriptCanvasSettingsRequestBus::Handler::BusDisconnect(); + AzToolsFramework::AssetSystemBus::Handler::BusDisconnect(); Clear(); @@ -831,16 +821,12 @@ namespace ScriptCanvasEditor connect(ui->action_ViewRestoreDefaultLayout, &QAction::triggered, this, &MainWindow::OnRestoreDefaultLayout); } - void MainWindow::SignalActiveSceneChanged(AZ::Data::AssetId assetId) + void MainWindow::SignalActiveSceneChanged(ScriptCanvasEditor::SourceHandle assetId) { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); - AZ::EntityId graphId; - - if (memoryAsset) + if (assetId.IsGraphValid()) { - graphId = memoryAsset->GetGraphId(); + EditorGraphRequestBus::EventResult(graphId, assetId.Get()->GetScriptCanvasId(), &EditorGraphRequests::GetGraphCanvasGraphId); } m_autoSaveTimer.stop(); @@ -859,18 +845,20 @@ namespace ScriptCanvasEditor GraphCanvas::ViewId viewId; GraphCanvas::SceneRequestBus::EventResult(viewId, graphId, &GraphCanvas::SceneRequests::GetViewId); - AZ_Assert(viewId.IsValid(), "SceneRequest must return a valid ViewId"); if (viewId.IsValid()) { GraphCanvas::ViewNotificationBus::Handler::BusDisconnect(); GraphCanvas::ViewNotificationBus::Handler::BusConnect(viewId); - enabled = memoryAsset->GetScriptCanvasId().IsValid(); + enabled = true; + } + else + { + AZ_Error("ScriptCanvasEditor", viewId.IsValid(), "SceneRequest must return a valid ViewId"); } } UpdateMenuState(enabled); - } void MainWindow::UpdateRecentMenu() @@ -922,18 +910,9 @@ namespace ScriptCanvasEditor return; } - AssetTrackerRequests::AssetList unsavedAssets; - AssetTrackerRequestBus::BroadcastResult(unsavedAssets, &AssetTrackerRequests::GetUnsavedAssets); - for (int tabCounter = 0; tabCounter < m_tabBar->count(); ++tabCounter) { - AZ::Data::AssetId assetId = m_tabBar->FindAssetId(tabCounter); - - auto resultIterator = m_processedClosedAssetIds.insert(assetId); - if (!resultIterator.second) - { - continue; - } + ScriptCanvasEditor::SourceHandle assetId = m_tabBar->FindAssetId(tabCounter); const Tracker::ScriptCanvasFileState& fileState = GetAssetFileState(assetId); @@ -950,29 +929,13 @@ namespace ScriptCanvasEditor if (shouldSaveResults == UnsavedChangesOptions::SAVE) { - Callbacks::OnSave saveCB = [this](bool isSuccessful, AZ::Data::AssetPtr, AZ::Data::AssetId) - { - if (isSuccessful) - { - // Continue closing. - qobject_cast(parent())->close(); - } - else - { - // Abort closing. - QMessageBox::critical(this, QString(), QObject::tr("Failed to save.")); - m_processedClosedAssetIds.clear(); - } - }; - ActivateAndSaveAsset(assetId, saveCB); + SaveAssetImpl(assetId, Save::InPlace); event->ignore(); return; } else if (shouldSaveResults == UnsavedChangesOptions::CANCEL_WITHOUT_SAVING) { - m_processedClosedAssetIds.clear(); event->ignore(); - return; } else if (shouldSaveResults == UnsavedChangesOptions::CONTINUE_WITHOUT_SAVING && @@ -984,20 +947,6 @@ namespace ScriptCanvasEditor } m_workspace->Save(); - - // Close all files. - - AssetTrackerRequests::AssetList allAssets; - AssetTrackerRequestBus::BroadcastResult(allAssets, &AssetTrackerRequests::GetAssets); - - for (auto trackedAsset : allAssets) - { - const AZ::Data::AssetId& assetId = trackedAsset->GetAsset().GetId(); - CloseScriptCanvasAsset(assetId); - } - - m_processedClosedAssetIds.clear(); - event->accept(); } @@ -1032,7 +981,7 @@ namespace ScriptCanvasEditor DequeuePropertyGridUpdate(); UndoRequestBus::Event(GetActiveScriptCanvasId(), &UndoRequests::Undo); - SignalSceneDirty(m_activeAssetId); + SignalSceneDirty(m_activeGraph); m_propertyGrid->ClearSelection(); GeneralEditorNotificationBus::Event(GetActiveScriptCanvasId(), &GeneralEditorNotifications::OnUndoRedoEnd); @@ -1044,7 +993,7 @@ namespace ScriptCanvasEditor DequeuePropertyGridUpdate(); UndoRequestBus::Event(GetActiveScriptCanvasId(), &UndoRequests::Redo); - SignalSceneDirty(m_activeAssetId); + SignalSceneDirty(m_activeGraph); m_propertyGrid->ClearSelection(); GeneralEditorNotificationBus::Event(GetActiveScriptCanvasId(), &GeneralEditorNotifications::OnUndoRedoEnd); @@ -1117,16 +1066,59 @@ namespace ScriptCanvasEditor { ScopedUndoBatch scopedUndoBatch("Modify Graph Canvas Scene"); UndoRequestBus::Event(scriptCanvasId, &UndoRequests::AddGraphItemChangeUndo, "Graph Change"); - MarkAssetModified(m_activeAssetId); + UpdateFileState(m_activeGraph, Tracker::ScriptCanvasFileState::MODIFIED); } const bool forceTimer = true; RestartAutoTimerSave(forceTimer); } - void MainWindow::SignalSceneDirty(AZ::Data::AssetId assetId) + void MainWindow::SourceFileChanged + ( [[maybe_unused]] AZStd::string relativePath + , AZStd::string scanFolder + , [[maybe_unused]] AZ::Uuid fileAssetId) { - MarkAssetModified(assetId); + auto handle = CompleteDescription(SourceHandle(nullptr, fileAssetId, {})); + if (handle) + { + if (!IsRecentSave(*handle)) + { + UpdateFileState(*handle, Tracker::ScriptCanvasFileState::MODIFIED); + } + else + { + AZ_TracePrintf + ( "ScriptCanvas" + , "Ignoring source file modification notification (possibly external), as a it was recently saved by the editor: %s" + , relativePath.c_str()); + } + } + } + + void MainWindow::SourceFileRemoved + ( AZStd::string relativePath + , [[maybe_unused]] AZStd::string scanFolder + , AZ::Uuid fileAssetId) + { + SourceHandle handle(nullptr, fileAssetId, relativePath); + { + if (!IsRecentSave(handle)) + { + UpdateFileState(handle, Tracker::ScriptCanvasFileState::SOURCE_REMOVED); + } + else + { + AZ_TracePrintf + ( "ScriptCanvas" + , "Ignoring source file removed notification (possibly external), as a it was recently saved by the editor: %s" + , relativePath.c_str()); + } + } + } + + void MainWindow::SignalSceneDirty(ScriptCanvasEditor::SourceHandle assetId) + { + UpdateFileState(assetId, Tracker::ScriptCanvasFileState::MODIFIED); } void MainWindow::PushPreventUndoStateUpdate() @@ -1147,62 +1139,14 @@ namespace ScriptCanvasEditor m_preventUndoStateUpdateCount = 0; } - void MainWindow::MarkAssetModified(const AZ::Data::AssetId& assetId) + void MainWindow::UpdateFileState(const ScriptCanvasEditor::SourceHandle& assetId, Tracker::ScriptCanvasFileState fileState) { - if (!assetId.IsValid()) - { - return; - } - - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); - - if (memoryAsset) - { - const auto& memoryAssetId = memoryAsset->GetId(); - const Tracker::ScriptCanvasFileState& fileState = GetAssetFileState(memoryAssetId); - if (fileState != Tracker::ScriptCanvasFileState::NEW) - { - AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::UpdateFileState, memoryAssetId, Tracker::ScriptCanvasFileState::MODIFIED); - } - } + m_tabBar->UpdateFileState(assetId, fileState); } - void MainWindow::RefreshScriptCanvasAsset(const AZ::Data::Asset& asset) + AZ::Outcome MainWindow::OpenScriptCanvasAssetId(const ScriptCanvasEditor::SourceHandle& fileAssetId, Tracker::ScriptCanvasFileState fileState) { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, asset.GetId()); - - if (memoryAsset && asset.IsReady()) - { - AZ::EntityId scGraphId = memoryAsset->GetScriptCanvasId(); - GraphCanvas::SceneNotificationBus::MultiHandler::BusDisconnect(scGraphId); - AZ::EntityId graphCanvasId = GetGraphCanvasGraphId(scGraphId); - - GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId, &GraphCanvas::AssetEditorNotifications::OnGraphRefreshed, graphCanvasId, graphCanvasId); - - int tabIndex = -1; - if (IsTabOpen(asset.GetId(), tabIndex)) - { - const AZStd::string& assetPath = memoryAsset->GetAbsolutePath(); - m_tabBar->setTabToolTip(tabIndex, assetPath.c_str()); - m_tabBar->SetTabText(tabIndex, memoryAsset->GetTabName().c_str(), memoryAsset->GetFileState()); - } - - if (graphCanvasId.IsValid()) - { - GraphCanvas::SceneNotificationBus::MultiHandler::BusConnect(graphCanvasId); - GraphCanvas::SceneMimeDelegateRequestBus::Event(graphCanvasId, &GraphCanvas::SceneMimeDelegateRequests::AddDelegate, m_entityMimeDelegateId); - - GraphCanvas::SceneRequestBus::Event(graphCanvasId, &GraphCanvas::SceneRequests::SetMimeType, Widget::NodePaletteDockWidget::GetMimeType()); - GraphCanvas::SceneMemberNotificationBus::Event(graphCanvasId, &GraphCanvas::SceneMemberNotifications::OnSceneReady); - } - } - } - - AZ::Outcome MainWindow::OpenScriptCanvasAssetId(const AZ::Data::AssetId& fileAssetId) - { - if (!fileAssetId.IsValid()) + if (fileAssetId.Id().IsNull()) { return AZ::Failure(AZStd::string("Unable to open asset with invalid asset id")); } @@ -1215,45 +1159,23 @@ namespace ScriptCanvasEditor return AZ::Success(outTabIndex); } - AZ::Data::AssetInfo assetInfo; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, fileAssetId); - - if (assetInfo.m_relativePath.empty()) + auto loadedGraph = LoadFromFile(fileAssetId.Path().c_str()); + if (!loadedGraph.IsSuccess()) { - return AZ::Failure(AZStd::string("Unknown AssetId")); + return AZ::Failure(AZStd::string("Failed to load graph at %s", fileAssetId.Path().c_str())); } - if (assetInfo.m_assetType != azrtti_typeid()) + outTabIndex = CreateAssetTab(loadedGraph.GetValue(), fileState); + + if (!m_isRestoringWorkspace) { - return AZ::Failure(AZStd::string("Invalid AssetId provided, it's not a Script Canvas supported type")); + SetActiveAsset(loadedGraph.GetValue()); } - AssetTrackerRequests::OnAssetReadyCallback onAssetReady = [this, fileAssetId, &outTabIndex](ScriptCanvasMemoryAsset& asset) - { - if (!asset.IsSourceInError()) - { - outTabIndex = CreateAssetTab(asset.GetFileAssetId()); - - if (!m_isRestoringWorkspace) - { - SetActiveAsset(fileAssetId); - } - - UpdateWorkspaceStatus(asset); - } - else - { - outTabIndex = -1; - m_loadingAssets.erase(fileAssetId); - } - }; - - m_loadingAssets.insert(fileAssetId); - - AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::Load, fileAssetId, assetInfo.m_assetType, onAssetReady); - if (outTabIndex >= 0) { + AddRecentFile(loadedGraph.GetValue().Path().c_str()); + OpenScriptCanvasAssetImplementation(loadedGraph.GetValue(), fileState); return AZ::Success(outTabIndex); } else @@ -1262,28 +1184,28 @@ namespace ScriptCanvasEditor } } - AZ::Outcome MainWindow::OpenScriptCanvasAsset(const ScriptCanvasMemoryAsset& scriptCanvasAsset, int tabIndex /*= -1*/) + AZ::Outcome MainWindow::OpenScriptCanvasAssetImplementation(const SourceHandle& scriptCanvasAsset, Tracker::ScriptCanvasFileState fileState, int tabIndex) { - const AZ::Data::AssetId& fileAssetId = scriptCanvasAsset.GetFileAssetId(); - if (!fileAssetId.IsValid()) + const ScriptCanvasEditor::SourceHandle& fileAssetId = scriptCanvasAsset; + if (!fileAssetId.IsDescriptionValid()) { return AZ::Failure(AZStd::string("Unable to open asset with invalid asset id")); } - if (scriptCanvasAsset.IsSourceInError()) + if (!scriptCanvasAsset.IsDescriptionValid()) { if (!m_isRestoringWorkspace) { - AZStd::string errorPath = scriptCanvasAsset.GetAbsolutePath(); + AZStd::string errorPath = scriptCanvasAsset.Path().c_str(); if (errorPath.empty()) { errorPath = m_errorFilePath; } - if (m_queuedFocusOverride == fileAssetId) + if (m_queuedFocusOverride.AnyEquals(fileAssetId)) { - m_queuedFocusOverride.SetInvalid(); + m_queuedFocusOverride = fileAssetId; } QMessageBox::warning(this, "Unable to open source file", QString("Source File(%1) is in error and cannot be opened").arg(errorPath.c_str()), QMessageBox::StandardButton::Ok); @@ -1304,113 +1226,67 @@ namespace ScriptCanvasEditor return AZ::Success(outTabIndex); } - outTabIndex = CreateAssetTab(fileAssetId, tabIndex); + outTabIndex = CreateAssetTab(fileAssetId, fileState, tabIndex); if (outTabIndex == -1) { - return AZ::Failure(AZStd::string::format("Unable to open existing Script Canvas Asset with id %s in the Script Canvas Editor", AssetHelpers::AssetIdToString(fileAssetId).c_str())); + return AZ::Failure(AZStd::string::format("Unable to open existing Script Canvas Asset with id %s in the Script Canvas Editor" + , fileAssetId.ToString().c_str())); } - AZStd::string assetPath = scriptCanvasAsset.GetAbsolutePath(); + AZStd::string assetPath = scriptCanvasAsset.Path().c_str(); if (!assetPath.empty() && !m_loadingNewlySavedFile) { - const size_t eraseCount = m_loadingWorkspaceAssets.erase(fileAssetId); - - if (eraseCount == 0) - { - AddRecentFile(assetPath.c_str()); - } + AddRecentFile(assetPath.c_str()); } - if (!m_isRestoringWorkspace) - { - SetActiveAsset(fileAssetId); - } - - GraphCanvas::GraphId graphCanvasGraphId = GetGraphCanvasGraphId(scriptCanvasAsset.GetScriptCanvasId()); + GraphCanvas::GraphId graphCanvasGraphId = GetGraphCanvasGraphId(scriptCanvasAsset.Get()->GetScriptCanvasId()); GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId, &GraphCanvas::AssetEditorNotifications::OnGraphLoaded, graphCanvasGraphId); - GeneralAssetNotificationBus::Event(fileAssetId, &GeneralAssetNotifications::OnAssetVisualized); - - AssetTrackerNotificationBus::MultiHandler::BusConnect(fileAssetId); - return AZ::Success(outTabIndex); } - AZ::Outcome MainWindow::OpenScriptCanvasAsset(AZ::Data::AssetId scriptCanvasAssetId, int tabIndex /*= -1*/) + AZ::Outcome MainWindow::OpenScriptCanvasAsset(ScriptCanvasEditor::SourceHandle scriptCanvasAssetId, Tracker::ScriptCanvasFileState fileState, int tabIndex) { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, scriptCanvasAssetId); - - // If the asset is already tracked we can go directly to opening it. - if (memoryAsset) + if (scriptCanvasAssetId.IsGraphValid()) { - return OpenScriptCanvasAsset(*memoryAsset, tabIndex); + return OpenScriptCanvasAssetImplementation(scriptCanvasAssetId, fileState, tabIndex); } else { - return OpenScriptCanvasAssetId(scriptCanvasAssetId); + return OpenScriptCanvasAssetId(scriptCanvasAssetId, fileState); } } - int MainWindow::CreateAssetTab(const AZ::Data::AssetId& assetId, int tabIndex) + int MainWindow::CreateAssetTab(const ScriptCanvasEditor::SourceHandle& assetId, Tracker::ScriptCanvasFileState fileState, int tabIndex) { - return m_tabBar->InsertGraphTab(tabIndex, assetId); + return m_tabBar->InsertGraphTab(tabIndex, assetId, fileState); } - AZ::Outcome MainWindow::UpdateScriptCanvasAsset(const AZ::Data::Asset& scriptCanvasAsset) + void MainWindow::RemoveScriptCanvasAsset(const ScriptCanvasEditor::SourceHandle& assetId) { - int outTabIndex = -1; - - PushPreventUndoStateUpdate(); - RefreshScriptCanvasAsset(scriptCanvasAsset); - if (IsTabOpen(scriptCanvasAsset.GetId(), outTabIndex)) - { - RefreshActiveAsset(); - } - PopPreventUndoStateUpdate(); - - if (outTabIndex == -1) - { - return AZ::Failure(AZStd::string::format("Script Canvas Asset %s is not open in a tab", scriptCanvasAsset.ToString().c_str())); - } - - return AZ::Success(outTabIndex); - } - - void MainWindow::RemoveScriptCanvasAsset(const AZ::Data::AssetId& assetId) - { - AssetHelpers::PrintInfo("RemoveScriptCanvasAsset : %s", AssetHelpers::AssetIdToString(assetId).c_str()); - + AssetHelpers::PrintInfo("RemoveScriptCanvasAsset : %s", assetId.ToString().c_str()); m_assetCreationRequests.erase(assetId); - GeneralAssetNotificationBus::Event(assetId, &GeneralAssetNotifications::OnAssetUnloaded); - AssetTrackerNotificationBus::MultiHandler::BusDisconnect(assetId); - - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); - - if (memoryAsset) + if (assetId.IsGraphValid()) { // Disconnect scene and asset editor buses - GraphCanvas::SceneNotificationBus::MultiHandler::BusDisconnect(memoryAsset->GetScriptCanvasId()); - GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId, &GraphCanvas::AssetEditorNotifications::OnGraphUnloaded, memoryAsset->GetGraphId()); + GraphCanvas::SceneNotificationBus::MultiHandler::BusDisconnect(assetId.Get()->GetScriptCanvasId()); + GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId + , &GraphCanvas::AssetEditorNotifications::OnGraphUnloaded, assetId.Get()->GetGraphCanvasGraphId()); } - AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::Close, assetId); - int tabIndex = m_tabBar->FindTab(assetId); QVariant tabdata = m_tabBar->tabData(tabIndex); if (tabdata.isValid()) { - auto tabAssetId = tabdata.value(); - SetActiveAsset(tabAssetId); + auto tabAssetId = tabdata.value(); + SetActiveAsset(tabAssetId.m_assetId); } - } - int MainWindow::CloseScriptCanvasAsset(const AZ::Data::AssetId& assetId) + int MainWindow::CloseScriptCanvasAsset(const ScriptCanvasEditor::SourceHandle& assetId) { int tabIndex = -1; if (IsTabOpen(assetId, tabIndex)) @@ -1427,35 +1303,32 @@ namespace ScriptCanvasEditor { if (createdAssetPair.second == requestingEntityId) { - return OpenScriptCanvasAssetId(createdAssetPair.first).IsSuccess(); + return OpenScriptCanvasAssetId(createdAssetPair.first, Tracker::ScriptCanvasFileState::NEW).IsSuccess(); } } - AZ::Data::AssetId previousAssetId = m_activeAssetId; + ScriptCanvasEditor::SourceHandle previousAssetId = m_activeGraph; OnFileNew(); - bool createdNewAsset = m_activeAssetId != previousAssetId; + bool createdNewAsset = !(m_activeGraph.AnyEquals(previousAssetId)); if (createdNewAsset) { - m_assetCreationRequests[m_activeAssetId] = requestingEntityId; + m_assetCreationRequests[m_activeGraph] = requestingEntityId; } if (m_isRestoringWorkspace) { - m_queuedFocusOverride = m_activeAssetId; + m_queuedFocusOverride = m_activeGraph; } return createdNewAsset; } - bool MainWindow::IsScriptCanvasAssetOpen(const AZ::Data::AssetId& assetId) const + bool MainWindow::IsScriptCanvasAssetOpen(const ScriptCanvasEditor::SourceHandle& assetId) const { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); - - return memoryAsset != nullptr; + return m_tabBar->FindTab(assetId) >= 0; } const CategoryInformation* MainWindow::FindNodePaletteCategoryInformation(AZStd::string_view categoryPath) const @@ -1468,107 +1341,57 @@ namespace ScriptCanvasEditor return m_nodePaletteModel.FindNodePaletteInformation(nodeType); } - void MainWindow::GetSuggestedFullFilenameToSaveAs(const AZ::Data::AssetId& assetId, AZStd::string& filePath, AZStd::string& fileFilter) - { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); - - AZStd::string assetPath; - if (memoryAsset) - { - assetPath = memoryAsset->GetAbsolutePath(); - - AZ::Data::AssetType assetType = memoryAsset->GetAsset().GetType(); - - ScriptCanvasAssetHandler* assetHandler; - AssetTrackerRequestBus::BroadcastResult(assetHandler, &AssetTrackerRequests::GetAssetHandlerForType, assetType); - AZ_Assert(assetHandler, "Asset type must have a valid asset handler"); - - AZ::EBusAggregateResults results; - AssetRegistryRequestBus::BroadcastResult(results, &AssetRegistryRequests::GetAssetDescription, assetType); - - ScriptCanvas::AssetDescription* description = nullptr; - for (auto item : results.values) - { - if (item->GetAssetType() == assetType) - { - description = item; - break; - } - } - - AZ_Assert(description, "Asset type must have a valid description"); - - fileFilter = description->GetFileFilterImpl(); - - AZStd::string tabName; - AssetTrackerRequestBus::BroadcastResult(tabName, &AssetTrackerRequests::GetTabName, assetId); - - assetPath = AZStd::string::format("%s/%s%s", description->GetSuggestedSavePathImpl(), tabName.c_str(), description->GetExtensionImpl()); - } - - AZStd::array resolvedPath; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(assetPath.data(), resolvedPath.data(), resolvedPath.size()); - filePath = resolvedPath.data(); - } - void MainWindow::OpenFile(const char* fullPath) { - m_errorFilePath = fullPath; + auto tabIndex = m_tabBar->FindTabByPath(fullPath); + if (tabIndex.IsGraphValid()) + { + SetActiveAsset(tabIndex); + return; + } - // Let's find the source file on disk AZStd::string watchFolder; AZ::Data::AssetInfo assetInfo; bool sourceInfoFound{}; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, fullPath, assetInfo, watchFolder); + AzToolsFramework::AssetSystemRequestBus::BroadcastResult + ( sourceInfoFound + , &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, fullPath, assetInfo, watchFolder); - if (sourceInfoFound) + if (!sourceInfoFound) { - const Tracker::ScriptCanvasFileState& fileState = GetAssetFileState(assetInfo.m_assetId); - if (fileState != Tracker::ScriptCanvasFileState::NEW && fileState != Tracker::ScriptCanvasFileState::INVALID) - { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetInfo.m_assetId); + QMessageBox::warning(this, "Invalid Source Asset", QString("'%1' is not a valid asset path.").arg(fullPath), QMessageBox::Ok); + m_errorFilePath = fullPath; + AZ_Warning("ScriptCanvas", false, "Unable to open file as a ScriptCanvas graph: %s", fullPath); + return; + } - if (m_tabBar->FindTab(assetInfo.m_assetId) < 0) - { - CreateAssetTab(assetInfo.m_assetId); - } + AZ::Outcome outcome = LoadFromFile(fullPath); + if (!outcome.IsSuccess()) + { + QMessageBox::warning(this, "Invalid Source File", QString("'%1' failed to load properly.").arg(fullPath), QMessageBox::Ok); + m_errorFilePath = fullPath; + AZ_Warning("ScriptCanvas", false, "Unable to open file as a ScriptCanvas graph: %s", fullPath); + return; + } - SetActiveAsset(memoryAsset->GetFileAssetId()); - OpenNextFile(); - return; - } - - Callbacks::OnAssetReadyCallback onAssetReady = [this, assetInfo](ScriptCanvasMemoryAsset&) - { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetInfo.m_assetId); - - auto openOutcome = OpenScriptCanvasAsset(*memoryAsset); - if (openOutcome) - { - RunGraphValidation(false); - SetRecentAssetId(assetInfo.m_assetId); - } - else - { - AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data()); - } - - OpenNextFile(); - }; - - // TODO-LS the assetInfo.m_assetType is always null for some reason, I know in this case we want default assets so it's ok to hardcode it - AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::Load, assetInfo.m_assetId, /*assetInfo.m_assetType*/azrtti_typeid(), onAssetReady); + m_errorFilePath.clear(); + auto activeGraph = ScriptCanvasEditor::SourceHandle(outcome.TakeValue(), assetInfo.m_assetId.m_guid, fullPath); + + auto openOutcome = OpenScriptCanvasAsset(activeGraph, Tracker::ScriptCanvasFileState::UNMODIFIED); + if (openOutcome) + { + RunGraphValidation(false); + SetActiveAsset(activeGraph); + SetRecentAssetId(activeGraph); } else { - QMessageBox::warning(this, "Invalid Source Asset", QString("'%1' is not a valid asset path.").arg(fullPath), QMessageBox::Ok); + AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data()); } } - GraphCanvas::Endpoint MainWindow::HandleProposedConnection(const GraphCanvas::GraphId&, const GraphCanvas::ConnectionId&, const GraphCanvas::Endpoint& endpoint, const GraphCanvas::NodeId& nodeId, const QPoint& screenPoint) + GraphCanvas::Endpoint MainWindow::HandleProposedConnection(const GraphCanvas::GraphId&, const GraphCanvas::ConnectionId& + , const GraphCanvas::Endpoint& endpoint, const GraphCanvas::NodeId& nodeId, const QPoint& screenPoint) { GraphCanvas::Endpoint retVal; @@ -1673,10 +1496,39 @@ namespace ScriptCanvasEditor void MainWindow::OnFileNew() { - MakeNewFile(); + static int scriptCanvasEditorDefaultNewNameCount = 0; + + AZStd::string assetPath; + + for (;;) + { + ScriptCanvasAssetDescription description; + AZStd::string newAssetName = AZStd::string::format(description.GetAssetNamePatternImpl(), ++scriptCanvasEditorDefaultNewNameCount); + + AZStd::array assetRootArray; + if (!AZ::IO::FileIOBase::GetInstance()->ResolvePath(description.GetSuggestedSavePathImpl() + , assetRootArray.data(), assetRootArray.size())) + { + AZ_ErrorOnce("Script Canvas", false, "Unable to resolve @projectroot@ path"); + } + + AzFramework::StringFunc::Path::Join(assetRootArray.data(), (newAssetName + description.GetExtensionImpl()).data(), assetPath); + AZ::Data::AssetInfo assetInfo; + + if (!AssetHelpers::GetAssetInfo(assetPath, assetInfo)) + { + break; + } + } + + auto createOutcome = CreateScriptCanvasAsset(assetPath); + if (!createOutcome.IsSuccess()) + { + AZ_Warning("Script Canvas", createOutcome, "%s", createOutcome.GetError().data()); + } } - int MainWindow::InsertTabForAsset(AZStd::string_view assetPath, AZ::Data::AssetId assetId, int tabIndex) + int MainWindow::InsertTabForAsset(AZStd::string_view assetPath, ScriptCanvasEditor::SourceHandle assetId, int tabIndex) { int outTabIndex = -1; @@ -1684,11 +1536,11 @@ namespace ScriptCanvasEditor // Insert tab block AZStd::string tabName; AzFramework::StringFunc::Path::GetFileName(assetPath.data(), tabName); - m_tabBar->InsertGraphTab(tabIndex, assetId); + m_tabBar->InsertGraphTab(tabIndex, assetId, Tracker::ScriptCanvasFileState::NEW); if (!IsTabOpen(assetId, outTabIndex)) { - AZ_Assert(false, AZStd::string::format("Unable to open new Script Canvas Asset with id %s in the Script Canvas Editor", AssetHelpers::AssetIdToString(assetId).c_str()).c_str()); + AZ_Assert(false, AZStd::string::format("Unable to open new Script Canvas Asset with id %s in the Script Canvas Editor", assetId.ToString().c_str()).c_str()); return -1; } @@ -1698,7 +1550,7 @@ namespace ScriptCanvasEditor return outTabIndex; } - void MainWindow::UpdateUndoCache(AZ::Data::AssetId) + void MainWindow::UpdateUndoCache(ScriptCanvasEditor::SourceHandle) { UndoCache* undoCache = nullptr; UndoRequestBus::EventResult(undoCache, GetActiveScriptCanvasId(), &UndoRequests::GetSceneUndoCache); @@ -1708,94 +1560,115 @@ namespace ScriptCanvasEditor } } - AZ::Outcome MainWindow::CreateScriptCanvasAsset(AZStd::string_view assetPath, AZ::Data::AssetType assetType, int tabIndex) + AZ::Outcome MainWindow::CreateScriptCanvasAsset(AZStd::string_view assetPath, int tabIndex) { int outTabIndex = -1; - AZ::Data::AssetId newAssetId; - auto onAssetCreated = [this, assetPath, tabIndex, &outTabIndex](ScriptCanvasMemoryAsset& asset) + ScriptCanvas::DataPtr graph = Graph::Create(); + AZ::Uuid assetId = AZ::Uuid::CreateRandom(); + ScriptCanvasEditor::SourceHandle handle = ScriptCanvasEditor::SourceHandle(graph, assetId, assetPath); + + outTabIndex = InsertTabForAsset(assetPath, handle, tabIndex); + + if (outTabIndex == -1) { - const AZ::Data::AssetId& assetId = asset.GetId(); + return AZ::Failure(AZStd::string::format("Script Canvas Asset %.*s is not open in a tab" + , static_cast(assetPath.size()), assetPath.data())); + } - outTabIndex = InsertTabForAsset(assetPath, assetId, tabIndex); + SetActiveAsset(handle); + PushPreventUndoStateUpdate(); - SetActiveAsset(assetId); + AZ::EntityId scriptCanvasEntityId = graph->GetGraph()->GetScriptCanvasId(); + GraphCanvas::SceneNotificationBus::MultiHandler::BusDisconnect(scriptCanvasEntityId); + AZ::EntityId graphCanvasGraphId = GetGraphCanvasGraphId(scriptCanvasEntityId); - UpdateScriptCanvasAsset(asset.GetAsset()); + GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId + , &GraphCanvas::AssetEditorNotifications::OnGraphRefreshed, graphCanvasGraphId, graphCanvasGraphId); - AZ::EntityId scriptCanvasEntityId; - AssetTrackerRequestBus::BroadcastResult(scriptCanvasEntityId, &AssetTrackerRequests::GetScriptCanvasId, assetId); + if (IsTabOpen(handle, tabIndex)) + { + AZStd::string tabName; + AzFramework::StringFunc::Path::GetFileName(assetPath.data(), tabName); + m_tabBar->setTabToolTip(tabIndex, assetPath.data()); + m_tabBar->SetTabText(tabIndex, tabName.c_str(), Tracker::ScriptCanvasFileState::NEW); + } - GraphCanvas::GraphId graphCanvasGraphId = GetGraphCanvasGraphId(scriptCanvasEntityId); - GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId, &GraphCanvas::AssetEditorNotifications::OnGraphLoaded, graphCanvasGraphId); + if (graphCanvasGraphId.IsValid()) + { + GraphCanvas::SceneNotificationBus::MultiHandler::BusConnect(graphCanvasGraphId); + GraphCanvas::SceneMimeDelegateRequestBus::Event(graphCanvasGraphId, &GraphCanvas::SceneMimeDelegateRequests::AddDelegate, m_entityMimeDelegateId); - }; - AssetTrackerRequestBus::BroadcastResult(newAssetId, &AssetTrackerRequests::Create, assetPath, assetType, onAssetCreated); + GraphCanvas::SceneRequestBus::Event(graphCanvasGraphId, &GraphCanvas::SceneRequests::SetMimeType, Widget::NodePaletteDockWidget::GetMimeType()); + GraphCanvas::SceneMemberNotificationBus::Event(graphCanvasGraphId, &GraphCanvas::SceneMemberNotifications::OnSceneReady); + } + + if (IsTabOpen(handle, outTabIndex)) + { + RefreshActiveAsset(); + } + + PopPreventUndoStateUpdate(); + + + GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId + , &GraphCanvas::AssetEditorNotifications::OnGraphLoaded, graphCanvasGraphId); return AZ::Success(outTabIndex); } - bool MainWindow::OnFileSave(const Callbacks::OnSave& saveCB) + bool MainWindow::OnFileSave() { - return SaveAssetImpl(m_activeAssetId, saveCB); + return SaveAssetImpl(m_activeGraph, Save::InPlace); } - bool MainWindow::OnFileSaveAs(const Callbacks::OnSave& saveCB) + bool MainWindow::OnFileSaveAs() { - return SaveAssetAsImpl(m_activeAssetId, saveCB); + return SaveAssetImpl(m_activeGraph, Save::As); } - bool MainWindow::SaveAssetImpl(const AZ::Data::AssetId& assetId, const Callbacks::OnSave& saveCB) + bool MainWindow::SaveAssetImpl(const ScriptCanvasEditor::SourceHandle& inMemoryAssetId, Save save) { - if (!assetId.IsValid()) + if (!inMemoryAssetId.IsGraphValid()) { return false; } - // TODO: Set graph read-only to prevent edits during save - - bool saveSuccessful = false; - - Tracker::ScriptCanvasFileState fileState = GetAssetFileState(assetId); - - if (fileState == Tracker::ScriptCanvasFileState::NEW) - { - saveSuccessful = SaveAssetAsImpl(assetId, saveCB); - } - else if (fileState == Tracker::ScriptCanvasFileState::MODIFIED - || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED) - { - SaveAsset(assetId, saveCB); - saveSuccessful = true; - } - - return saveSuccessful; - } - - bool MainWindow::SaveAssetAsImpl(const AZ::Data::AssetId& inMemoryAssetId, const Callbacks::OnSave& saveCB) - { - if (!inMemoryAssetId.IsValid()) - { - return false; - } - - if (m_activeAssetId != inMemoryAssetId) + if (!m_activeGraph.AnyEquals(inMemoryAssetId)) { OnChangeActiveGraphTab(inMemoryAssetId); } PrepareAssetForSave(inMemoryAssetId); + ScriptCanvasAssetDescription assetDescription; AZStd::string suggestedFilename; AZStd::string suggestedFileFilter; - GetSuggestedFullFilenameToSaveAs(inMemoryAssetId, suggestedFilename, suggestedFileFilter); - - EnsureSaveDestinationDirectory(suggestedFilename); - - QString filter = suggestedFileFilter.c_str(); - QString selectedFile; - bool isValidFileName = false; + + if (save == Save::InPlace) + { + isValidFileName = true; + suggestedFileFilter = ScriptCanvasAssetDescription().GetExtensionImpl(); + suggestedFilename = inMemoryAssetId.Path().c_str(); + } + else + { + suggestedFileFilter = ScriptCanvasAssetDescription().GetExtensionImpl(); + + if (inMemoryAssetId.Path().empty()) + { + suggestedFilename = ScriptCanvasAssetDescription().GetSuggestedSavePathImpl(); + } + else + { + suggestedFilename = inMemoryAssetId.Path().c_str(); + } + } + + EnsureSaveDestinationDirectory(suggestedFilename); + QString filter = suggestedFileFilter.c_str(); + QString selectedFile = suggestedFilename.c_str(); while (!isValidFileName) { @@ -1806,6 +1679,12 @@ namespace ScriptCanvasEditor if (!selectedFile.isEmpty()) { AZStd::string filePath = selectedFile.toUtf8().data(); + + if (!AZ::StringFunc::EndsWith(filePath, assetDescription.GetExtensionImpl(), false)) + { + filePath += assetDescription.GetExtensionImpl(); + } + AZStd::string fileName; // Verify that the path is within the project @@ -1815,11 +1694,7 @@ namespace ScriptCanvasEditor AZ::IO::FileIOBase::GetInstance()->ResolvePath("@engroot@", assetRootChar.data(), assetRootChar.size()); assetRoot = assetRootChar.data(); - /* if (!AZ::StringFunc::StartsWith(filePath, assetRoot)) - { - QMessageBox::information(this, "Unable to Save", AZStd::string::format("You must select a path within the current project\n\n%s", assetRoot.c_str()).c_str()); - } - else*/ if (AzFramework::StringFunc::Path::GetFileName(filePath.c_str(), fileName)) + if (AzFramework::StringFunc::Path::GetFileName(filePath.c_str(), fileName)) { isValidFileName = !(fileName.empty()); } @@ -1827,7 +1702,6 @@ namespace ScriptCanvasEditor { QMessageBox::information(this, "Unable to Save", "File name cannot be empty"); } - } else { @@ -1839,128 +1713,134 @@ namespace ScriptCanvasEditor { AZStd::string internalStringFile = selectedFile.toUtf8().data(); + + if (!AZ::StringFunc::EndsWith(internalStringFile, assetDescription.GetExtensionImpl(), false)) + { + internalStringFile += assetDescription.GetExtensionImpl(); + } + if (!AssetHelpers::IsValidSourceFile(internalStringFile, GetActiveScriptCanvasId())) { QMessageBox::warning(this, "Unable to Save", QString("File\n'%1'\n\nDoes not match the asset type of the current Graph.").arg(selectedFile)); return false; } - SaveNewAsset(internalStringFile, inMemoryAssetId, saveCB); - + SaveAs(internalStringFile, inMemoryAssetId); m_newlySavedFile = internalStringFile; - // Forcing the file add here, since we are creating a new file AddRecentFile(m_newlySavedFile.c_str()); - return true; } return false; } - - void MainWindow::OnSaveCallback(bool saveSuccess, AZ::Data::AssetPtr fileAsset, AZ::Data::AssetId previousFileAssetId) + + void MainWindow::OnSaveCallBack(const VersionExplorer::FileSaveResult& result) { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AZStd::string tabName = m_tabBar->tabText(m_tabBar->currentIndex()).toUtf8().data(); - - int saveTabIndex = m_tabBar->currentIndex(); + const bool saveSuccess = result.fileSaveError.empty(); + auto completeDescription = CompleteDescription(m_fileSaver->GetSource()); + auto memoryAsset = completeDescription ? *completeDescription : m_fileSaver->GetSource(); + int saveTabIndex = m_tabBar->FindTab(memoryAsset); + AZStd::string tabName = saveTabIndex >= 0 ? m_tabBar->tabText(saveTabIndex).toUtf8().data() : ""; if (saveSuccess) { - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, fileAsset->GetId()); - AZ_Assert(memoryAsset, "At this point we must have a MemoryAsset"); + ScriptCanvasEditor::SourceHandle& fileAssetId = memoryAsset; + int currentTabIndex = m_tabBar->currentIndex(); - // Update the editor with the new information about this asset. - const AZ::Data::AssetId& fileAssetId = memoryAsset->GetFileAssetId(); + AZ::Data::AssetId oldId = fileAssetId.Id(); + AZ::Data::AssetInfo assetInfo; + assetInfo.m_assetId = fileAssetId.Id(); + AZ_VerifyWarning("ScriptCanvas", AssetHelpers::GetAssetInfo(fileAssetId.Path().c_str(), assetInfo) + , "Failed to find asset info for source file just saved: %s", fileAssetId.Path().c_str()); - saveTabIndex = m_tabBar->FindTab(fileAssetId); + const bool assetIdHasChanged = assetInfo.m_assetId.m_guid != fileAssetId.Id(); + fileAssetId = SourceHandle(fileAssetId, assetInfo.m_assetId.m_guid, fileAssetId.Path()); + // check for saving a graph over another graph with an open tab + for (;;) + { + auto graph = fileAssetId.Get(); + int tabIndexByGraph = m_tabBar->FindTab(graph); + if (tabIndexByGraph == -1) + { + AZ_Warning("ScriptCanvas", false, "unable to find graph just saved"); + break; + } + + int saveOverMatch = m_tabBar->FindSaveOverMatch(fileAssetId); + if (saveOverMatch < 0) + { + saveTabIndex = tabIndexByGraph; + currentTabIndex = m_tabBar->currentIndex(); + break; + } + + m_tabBar->CloseTab(saveOverMatch); + } + + // this path is questionable, this is a save request that is not the current graph // We've saved as over a new graph, so we need to close the old one. - if (saveTabIndex != m_tabBar->currentIndex()) + if (saveTabIndex != currentTabIndex) { // Invalidate the file asset id so we don't delete trigger the asset flow. - m_tabBar->setTabData(saveTabIndex, QVariant::fromValue(AZ::Data::AssetId())); - + m_tabBar->setTabData(saveTabIndex, QVariant::fromValue(Widget::GraphTabMetadata())); m_tabBar->CloseTab(saveTabIndex); saveTabIndex = -1; } - if (saveTabIndex < 0) + AzFramework::StringFunc::Path::GetFileName(memoryAsset.Path().c_str(), tabName); + + if (assetIdHasChanged) { - // This asset had not been saved yet, we will need to use the in memory asset Id to get the index. - saveTabIndex = m_tabBar->FindTab(memoryAsset->GetId()); + auto entity = memoryAsset.Get()->GetEntity(); - if (saveTabIndex < 0) - { - // Finally, we may have Saved-As and we need the previous file asset Id to find the tab - saveTabIndex = m_tabBar->FindTab(previousFileAssetId); - } - } - - AzFramework::StringFunc::Path::GetFileName(memoryAsset->GetAbsolutePath().c_str(), tabName); - - // Update the tab's assetId to the file asset Id (necessary when saving a new asset) - m_tabBar->ConfigureTab(saveTabIndex, fileAssetId, tabName); - - GeneralAssetNotificationBus::Event(memoryAsset->GetId(), &GeneralAssetNotifications::OnAssetVisualized); - - auto requestorIter = m_assetCreationRequests.find(fileAsset->GetId()); - - if (requestorIter != m_assetCreationRequests.end()) - { - auto editorComponents = AZ::EntityUtils::FindDerivedComponents(requestorIter->second.first); + auto editorComponents = AZ::EntityUtils::FindDerivedComponents(entity); if (editorComponents.empty()) { - auto firstRequestBus = EditorScriptCanvasComponentRequestBus::FindFirstHandler(requestorIter->second.first); - - if (firstRequestBus) + if (auto firstRequestBus = EditorScriptCanvasComponentRequestBus::FindFirstHandler(entity->GetId())) { - firstRequestBus->SetAssetId(fileAsset->GetId()); + firstRequestBus->SetAssetId(memoryAsset.Describe()); } } else { for (auto editorComponent : editorComponents) { - if (editorComponent->GetId() == requestorIter->second.second) + if (editorComponent->GetAssetId() == oldId) { - editorComponent->SetAssetId(fileAsset->GetId()); + editorComponent->SetAssetId(memoryAsset.Describe()); break; } } } - - m_assetCreationRequests.erase(requestorIter); - } + } // Soft switch the asset id here. We'll do a double scene switch down below to actually switch the active assetid - m_activeAssetId = fileAssetId; - } - else - { - // Use the previous memory asset to find what we had setup as our display - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeAssetId); + m_activeGraph = fileAssetId; - // Drop off our file modifier status for our display name when we fail to save. - if (tabName.at(tabName.size() -1) == '*') + if (tabName.at(tabName.size() - 1) == '*' || tabName.at(tabName.size() - 1) == '^') { tabName = tabName.substr(0, tabName.size() - 2); } + + auto tabData = m_tabBar->GetTabData(saveTabIndex); + tabData->m_fileState = Tracker::ScriptCanvasFileState::UNMODIFIED; + tabData->m_assetId = fileAssetId; + m_tabBar->SetTabData(*tabData, saveTabIndex); + m_tabBar->SetTabText(saveTabIndex, tabName.c_str()); + } + else + { + const auto failureMessage = AZStd::string::format("Failed to save %s: %s", tabName.c_str(), result.fileSaveError.c_str()); + QMessageBox::critical(this, QString(), QObject::tr(failureMessage.data())); } if (m_tabBar->currentIndex() != saveTabIndex) { m_tabBar->setCurrentIndex(saveTabIndex); } - else - { - // Something weird happens with our saving. Where we are relying on these scene changes being called. - AZ::Data::AssetId previousAssetId = m_activeAssetId; - - OnChangeActiveGraphTab(AZ::Data::AssetId()); - OnChangeActiveGraphTab(previousAssetId); - } UpdateAssignToSelectionState(); @@ -1969,91 +1849,38 @@ namespace ScriptCanvasEditor const bool displayAsNotification = true; RunGraphValidation(displayAsNotification); - // This is called during saving, so the is scaving flag is always true Need to update the state after this callback is complete. So schedule for next system tick. - AddSystemTickAction(SystemTickActionFlag::UpdateSaveMenuState); - - if (m_closeCurrentGraphAfterSave) - { - AddSystemTickAction(SystemTickActionFlag::CloseCurrentGraph); - } - m_closeCurrentGraphAfterSave = false; EnableAssetView(memoryAsset); + UpdateSaveState(true); UnblockCloseRequests(); + m_fileSaver.reset(); } - bool MainWindow::ActivateAndSaveAsset(const AZ::Data::AssetId& unsavedAssetId, const Callbacks::OnSave& saveCB) + bool MainWindow::ActivateAndSaveAsset(const ScriptCanvasEditor::SourceHandle& unsavedAssetId) { SetActiveAsset(unsavedAssetId); - return OnFileSave(saveCB); + return OnFileSave(); } - void MainWindow::SaveAsset(AZ::Data::AssetId assetId, const Callbacks::OnSave& onSave) + void MainWindow::SaveAs(AZStd::string_view path, ScriptCanvasEditor::SourceHandle inMemoryAssetId) { - PrepareAssetForSave(assetId); + DisableAssetView(inMemoryAssetId); + UpdateSaveState(false); + m_fileSaver = AZStd::make_unique + ( nullptr + , [this](const VersionExplorer::FileSaveResult& fileSaveResult) { OnSaveCallBack(fileSaveResult); }); - auto onSaveCallback = [this, onSave](bool saveSuccess, AZ::Data::AssetPtr asset, AZ::Data::AssetId previousAssetId) - { - OnSaveCallback(saveSuccess, asset, previousAssetId); - if (onSave) - { - AZStd::invoke(onSave, saveSuccess, asset, previousAssetId); - } - }; + ScriptCanvasEditor::SourceHandle newLocation(inMemoryAssetId, AZ::Uuid::CreateNull(), path); + MarkRecentSave(newLocation); + m_fileSaver->Save(newLocation); - AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::Save, assetId, onSaveCallback); - UpdateSaveState(); - - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeAssetId); - - // Disable the current view if we are saving. - if (memoryAsset) - { - DisableAssetView(memoryAsset); - } - - BlockCloseRequests(); - } - - void MainWindow::SaveNewAsset(AZStd::string_view path, AZ::Data::AssetId inMemoryAssetId, const Callbacks::OnSave& onSave) - { - PrepareAssetForSave(inMemoryAssetId); - - auto onSaveCallback = [this, onSave](bool saveSuccess, AZ::Data::AssetPtr asset, AZ::Data::AssetId previousAssetId) - { - OnSaveCallback(saveSuccess, asset, previousAssetId); - if (onSave) - { - AZStd::invoke(onSave, saveSuccess, asset, previousAssetId); - } - }; - AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::SaveAs, inMemoryAssetId, path, onSaveCallback); - - UpdateSaveState(); - - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, inMemoryAssetId); - - // Disable the current view if we are saving. - if (memoryAsset) - { - DisableAssetView(memoryAsset); - } - - BlockCloseRequests(); + BlockCloseRequests(); } void MainWindow::OnFileOpen() { - AZ::SerializeContext* serializeContext = nullptr; - EBUS_EVENT_RESULT(serializeContext, AZ::ComponentApplicationBus, GetSerializeContext); - AZ_Assert(serializeContext, "Failed to acquire application serialize context."); - - AZ::Data::AssetId openId = ReadRecentAssetId(); - AZStd::string assetRoot; { AZStd::array assetRootChar; @@ -2061,33 +1888,10 @@ namespace ScriptCanvasEditor assetRoot = assetRootChar.data(); } - AZStd::string assetPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, openId); - if (!assetPath.empty()) - { - assetPath = AZStd::string::format("%s/%s", assetRoot.c_str(), assetPath.c_str()); - } - - if (!openId.IsValid() || !QFile::exists(assetPath.c_str())) - { - assetPath = AZStd::string::format("%s/scriptcanvas", assetRoot.c_str()); - } - assetPath = AZStd::string::format("%s/scriptcanvas", assetRoot.c_str()); - - AZ::EBusAggregateResults> fileFilters; - AssetRegistryRequestBus::BroadcastResult(fileFilters, &AssetRegistryRequests::GetAssetHandlerFileFilters); - + AZStd::string assetPath = AZStd::string::format("%s/scriptcanvas", assetRoot.c_str()); QString filter; - AZStd::set filterSet; - auto aggregateFilters = fileFilters.values; - for (auto aggregateFilters2 : fileFilters.values) - { - for (const AZStd::string& fileFilter : aggregateFilters2) - { - filterSet.insert(fileFilter); - } - } + AZStd::set filterSet { ".scriptcanvas" }; QStringList nameFilters; @@ -2454,31 +2258,6 @@ namespace ScriptCanvasEditor GraphCanvas::ViewRequestBus::Event(viewId, &GraphCanvas::ViewRequests::CenterOnEndOfChain); } - void MainWindow::UpdateWorkspaceStatus(const ScriptCanvasMemoryAsset& memoryAsset) - { - AZ::Data::AssetId fileAssetId = memoryAsset.GetFileAssetId(); - - size_t eraseCount = m_loadingAssets.erase(fileAssetId); - - if (eraseCount > 0) - { - AZStd::string rootFilePath; - AZ::Data::AssetInfo assetInfo = AssetHelpers::GetAssetInfo(fileAssetId, rootFilePath); - - // Don't want to use the join since I don't want the normalized path - if (!rootFilePath.empty() && !assetInfo.m_relativePath.empty()) - { - eraseCount = m_loadingWorkspaceAssets.erase(fileAssetId); - - if (eraseCount == 0) - { - AZStd::string fullPath = AZStd::string::format("%s/%s", rootFilePath.c_str(), assetInfo.m_relativePath.c_str()); - AddRecentFile(fullPath.c_str()); - } - } - } - } - void MainWindow::OnCanUndoChanged(bool canUndo) { ui->action_Undo->setEnabled(canUndo); @@ -2519,7 +2298,7 @@ namespace ScriptCanvasEditor { if (m_allowAutoSave) { - const Tracker::ScriptCanvasFileState& fileState = GetAssetFileState(m_activeAssetId); + const Tracker::ScriptCanvasFileState& fileState = GetAssetFileState(m_activeGraph); if (fileState != Tracker::ScriptCanvasFileState::INVALID && fileState != Tracker::ScriptCanvasFileState::NEW) { OnFileSaveCaller(); @@ -2528,52 +2307,57 @@ namespace ScriptCanvasEditor } //! GeneralRequestBus - void MainWindow::OnChangeActiveGraphTab(AZ::Data::AssetId assetId) + void MainWindow::OnChangeActiveGraphTab(ScriptCanvasEditor::SourceHandle assetId) { SetActiveAsset(assetId); } AZ::EntityId MainWindow::GetActiveGraphCanvasGraphId() const { - AZ::EntityId graphId; - AssetTrackerRequestBus::BroadcastResult(graphId, &AssetTrackerRequests::GetGraphId, m_activeAssetId); + AZ::EntityId graphId{}; + + if (m_activeGraph.IsGraphValid()) + { + EditorGraphRequestBus::EventResult + ( graphId, m_activeGraph.Get()->GetScriptCanvasId(), &EditorGraphRequests::GetGraphCanvasGraphId); + } + return graphId; } ScriptCanvas::ScriptCanvasId MainWindow::GetActiveScriptCanvasId() const { - ScriptCanvas::ScriptCanvasId sceneId; - AssetTrackerRequestBus::BroadcastResult(sceneId, &AssetTrackerRequests::GetScriptCanvasId, m_activeAssetId); - return sceneId; + return FindScriptCanvasIdByAssetId(m_activeGraph); } GraphCanvas::GraphId MainWindow::GetGraphCanvasGraphId(const ScriptCanvas::ScriptCanvasId& scriptCanvasId) const { - AZ::EntityId graphCanvasId; - AssetTrackerRequestBus::BroadcastResult(graphCanvasId, &AssetTrackerRequests::GetGraphCanvasId, scriptCanvasId); - - return graphCanvasId; - } - - GraphCanvas::GraphId MainWindow::FindGraphCanvasGraphIdByAssetId(const AZ::Data::AssetId& assetId) const - { - AZ::EntityId graphId; - AssetTrackerRequestBus::BroadcastResult(graphId, &AssetTrackerRequests::GetGraphId, assetId); + AZ::EntityId graphId{}; + EditorGraphRequestBus::EventResult(graphId, scriptCanvasId, &EditorGraphRequests::GetGraphCanvasGraphId); return graphId; } - ScriptCanvas::ScriptCanvasId MainWindow::FindScriptCanvasIdByAssetId(const AZ::Data::AssetId& assetId) const + GraphCanvas::GraphId MainWindow::FindGraphCanvasGraphIdByAssetId(const ScriptCanvasEditor::SourceHandle& assetId) const { - ScriptCanvas::ScriptCanvasId scriptCanvasId; - AssetTrackerRequestBus::BroadcastResult(scriptCanvasId, &AssetTrackerRequests::GetScriptCanvasId, assetId); - return scriptCanvasId; + AZ::EntityId graphId{}; + + if (assetId.IsGraphValid()) + { + EditorGraphRequestBus::EventResult + ( graphId, assetId.Get()->GetScriptCanvasId(), &EditorGraphRequests::GetGraphCanvasGraphId); + } + + return graphId; + } + + ScriptCanvas::ScriptCanvasId MainWindow::FindScriptCanvasIdByAssetId(const ScriptCanvasEditor::SourceHandle& assetId) const + { + return assetId.IsGraphValid() ? assetId.Get()->GetScriptCanvasId() : ScriptCanvas::ScriptCanvasId{}; } ScriptCanvas::ScriptCanvasId MainWindow::GetScriptCanvasId(const GraphCanvas::GraphId& graphCanvasGraphId) const { - ScriptCanvas::ScriptCanvasId scriptCanvasId; - AssetTrackerRequestBus::BroadcastResult(scriptCanvasId, &AssetTrackerRequests::GetScriptCanvasIdFromGraphId, graphCanvasGraphId); - return scriptCanvasId; + return m_tabBar->FindScriptCanvasIdFromGraphCanvasId(graphCanvasGraphId); } bool MainWindow::IsInUndoRedo(const AZ::EntityId& graphCanvasGraphId) const @@ -2602,15 +2386,15 @@ namespace ScriptCanvasEditor return isActive; } - QVariant MainWindow::GetTabData(const AZ::Data::AssetId& assetId) + QVariant MainWindow::GetTabData(const ScriptCanvasEditor::SourceHandle& assetId) { for (int tabIndex = 0; tabIndex < m_tabBar->count(); ++tabIndex) { QVariant tabdata = m_tabBar->tabData(tabIndex); if (tabdata.isValid()) { - auto tabAssetId = tabdata.value(); - if (tabAssetId == assetId) + auto tabAssetId = tabdata.value(); + if (tabAssetId.m_assetId.AnyEquals(assetId)) { return tabdata; } @@ -2619,7 +2403,7 @@ namespace ScriptCanvasEditor return QVariant(); } - bool MainWindow::IsTabOpen(const AZ::Data::AssetId& fileAssetId, int& outTabIndex) const + bool MainWindow::IsTabOpen(const ScriptCanvasEditor::SourceHandle& fileAssetId, int& outTabIndex) const { int tabIndex = m_tabBar->FindTab(fileAssetId); if (-1 != tabIndex) @@ -2630,27 +2414,22 @@ namespace ScriptCanvasEditor return false; } - void MainWindow::ReconnectSceneBuses(AZ::Data::AssetId previousAssetId, AZ::Data::AssetId nextAssetId) + void MainWindow::ReconnectSceneBuses(ScriptCanvasEditor::SourceHandle previousAsset, ScriptCanvasEditor::SourceHandle nextAsset) { - ScriptCanvasMemoryAsset::pointer previousAsset; - AssetTrackerRequestBus::BroadcastResult(previousAsset, &AssetTrackerRequests::GetAsset, previousAssetId); - - ScriptCanvasMemoryAsset::pointer nextAsset; - AssetTrackerRequestBus::BroadcastResult(nextAsset, &AssetTrackerRequests::GetAsset, nextAssetId); - // Disconnect previous asset AZ::EntityId previousScriptCanvasSceneId; - if (previousAsset) - { - previousScriptCanvasSceneId = previousAsset->GetScriptCanvasId(); + if (previousAsset.IsGraphValid()) + { + previousScriptCanvasSceneId = previousAsset.Get()->GetScriptCanvasId(); GraphCanvas::SceneNotificationBus::MultiHandler::BusDisconnect(previousScriptCanvasSceneId); } AZ::EntityId nextAssetGraphCanvasId; - if (nextAsset) + if (nextAsset.IsGraphValid()) { // Connect the next asset - nextAssetGraphCanvasId = nextAsset->GetGraphId(); + EditorGraphRequestBus::EventResult(nextAssetGraphCanvasId, nextAsset.Get()->GetScriptCanvasId(), &EditorGraphRequests::GetGraphCanvasGraphId); + if (nextAssetGraphCanvasId.IsValid()) { GraphCanvas::SceneNotificationBus::MultiHandler::BusConnect(nextAssetGraphCanvasId); @@ -2663,19 +2442,18 @@ namespace ScriptCanvasEditor // Notify about the graph refresh GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId, &GraphCanvas::AssetEditorNotifications::OnGraphRefreshed, previousScriptCanvasSceneId, nextAssetGraphCanvasId); - } - void MainWindow::SetActiveAsset(const AZ::Data::AssetId& fileAssetId) + void MainWindow::SetActiveAsset(const ScriptCanvasEditor::SourceHandle& fileAssetId) { - if (m_activeAssetId == fileAssetId) + if (m_activeGraph.AnyEquals(fileAssetId)) { return; } - AssetHelpers::PrintInfo("SetActiveAsset : from: %s to %s", AssetHelpers::AssetIdToString(m_activeAssetId).c_str(), AssetHelpers::AssetIdToString(fileAssetId).c_str()); + AssetHelpers::PrintInfo("SetActiveAsset : from: %s to %s", m_activeGraph.ToString().c_str(), fileAssetId.ToString().c_str()); - if (fileAssetId.IsValid()) + if (fileAssetId.IsGraphValid()) { if (m_tabBar->FindTab(fileAssetId) >= 0) { @@ -2688,87 +2466,54 @@ namespace ScriptCanvasEditor } } - if (m_activeAssetId.IsValid()) + if (m_activeGraph.IsGraphValid()) { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeAssetId); - // If we are saving the asset, the Id may have changed from the in-memory to the file asset Id, in that case, // there's no need to hide the view or remove the widget - if (memoryAsset && memoryAsset->GetView()) + auto oldTab = m_tabBar->FindTab(m_activeGraph); + if (auto view = m_tabBar->ModTabView(oldTab)) { - memoryAsset->GetView()->hide(); - m_layout->removeWidget(memoryAsset->GetView()); + view->hide(); + m_layout->removeWidget(view); + m_tabBar->ClearTabView(oldTab); } } - if (fileAssetId.IsValid()) + if (fileAssetId.IsGraphValid()) { - AZ::Data::AssetId previousAssetId = m_activeAssetId; - - m_activeAssetId = fileAssetId; + ScriptCanvasEditor::SourceHandle previousAssetId = m_activeGraph; + m_activeGraph = fileAssetId; RefreshActiveAsset(); - - ReconnectSceneBuses(previousAssetId, m_activeAssetId); + ReconnectSceneBuses(previousAssetId, m_activeGraph); } else { - AZ::Data::AssetId previousAssetId = m_activeAssetId; - - m_activeAssetId.SetInvalid(); + ScriptCanvasEditor::SourceHandle previousAssetId = m_activeGraph; + m_activeGraph.Clear(); m_emptyCanvas->show(); - - ReconnectSceneBuses(previousAssetId, m_activeAssetId); - - SignalActiveSceneChanged(AZ::Data::AssetId()); + ReconnectSceneBuses(previousAssetId, m_activeGraph); + SignalActiveSceneChanged(ScriptCanvasEditor::SourceHandle()); } UpdateUndoCache(fileAssetId); - - RefreshSelection(); + RefreshSelection(); } void MainWindow::RefreshActiveAsset() { - if (m_activeAssetId.IsValid()) + if (m_activeGraph.IsGraphValid()) { - AssetHelpers::PrintInfo("RefreshActiveAsset : m_activeAssetId (%s)", AssetHelpers::AssetIdToString(m_activeAssetId).c_str()); - - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeAssetId); - - if (memoryAsset) + AssetHelpers::PrintInfo("RefreshActiveAsset : m_activeGraph (%s)", m_activeGraph.ToString().c_str()); + if (auto view = m_tabBar->ModOrCreateTabView(m_tabBar->FindTab(m_activeGraph))) { - AZ::EntityId sceneEntityId = memoryAsset->GetScriptCanvasId(); - - const auto& scriptCanvasAsset = memoryAsset->GetAsset(); - - if (scriptCanvasAsset.IsReady() && scriptCanvasAsset.Get()->GetScriptCanvasEntity()->GetState() == AZ::Entity::State::Active) - { - if (!memoryAsset->GetView()) - { - memoryAsset->CreateView(m_tabBar); - } - - auto view = memoryAsset->GetView(); - AZ_Assert(view, "Asset should have a view"); - if (view) - { - AssetHelpers::PrintInfo("RefreshActiveAsset : m_activeAssetId (%s)", AssetHelpers::AssetIdToString(m_activeAssetId).c_str()); - - view->ShowScene(sceneEntityId); - m_layout->addWidget(view); - view->show(); - - m_emptyCanvas->hide(); - } - - SignalActiveSceneChanged(m_activeAssetId); - } + view->ShowScene(m_activeGraph.Get()->GetScriptCanvasId()); + m_layout->addWidget(view); + view->show(); + m_emptyCanvas->hide(); + SignalActiveSceneChanged(m_activeGraph); } else { - // If we couldn't load a memory asset for our active asset. Just set ourselves to invalid. SetActiveAsset({}); } } @@ -2777,15 +2522,6 @@ namespace ScriptCanvasEditor void MainWindow::Clear() { m_tabBar->CloseAllTabs(); - - AssetTrackerRequests::AssetList assets; - AssetTrackerRequestBus::BroadcastResult(assets, &AssetTrackerRequests::GetAssets); - - for (auto asset : assets) - { - RemoveScriptCanvasAsset(asset->GetAsset().GetId()); - } - SetActiveAsset({}); } @@ -2794,61 +2530,22 @@ namespace ScriptCanvasEditor QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) { - auto fileAssetId = tabdata.value(); - - Tracker::ScriptCanvasFileState fileState; - AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, fileAssetId); - - bool isSaving = false; - AssetTrackerRequestBus::BroadcastResult(isSaving, &AssetTrackerRequests::IsSaving, fileAssetId); - - if (isSaving) - { - m_closeCurrentGraphAfterSave = true; - return; - } - + Widget::GraphTabMetadata tabMetadata = tabdata.value(); + Tracker::ScriptCanvasFileState fileState = tabMetadata.m_fileState; UnsavedChangesOptions saveDialogResults = UnsavedChangesOptions::CONTINUE_WITHOUT_SAVING; - if (!isSaving && (fileState == Tracker::ScriptCanvasFileState::NEW || fileState == Tracker::ScriptCanvasFileState::MODIFIED || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED)) + + if (fileState == Tracker::ScriptCanvasFileState::NEW + || fileState == Tracker::ScriptCanvasFileState::MODIFIED + || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED) { - SetActiveAsset(fileAssetId); - - AZStd::string tabName; - AssetTrackerRequestBus::BroadcastResult(tabName, &AssetTrackerRequests::GetTabName, fileAssetId); - - saveDialogResults = ShowSaveDialog(tabName.c_str()); + SetActiveAsset(tabMetadata.m_assetId); + saveDialogResults = ShowSaveDialog(m_tabBar->tabText(index).toUtf8().constData()); } if (saveDialogResults == UnsavedChangesOptions::SAVE) { - auto saveCB = [this](bool isSuccessful, AZ::Data::AssetPtr asset, AZ::Data::AssetId) - { - if (isSuccessful) - { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, asset->GetId()); - AZ_Assert(memoryAsset, "At this point we must have a MemoryAsset"); - - int tabIndex = -1; - if (IsTabOpen(memoryAsset->GetFileAssetId(), tabIndex)) - { - OnTabCloseRequest(tabIndex); - } - } - else - { - QMessageBox::critical(this, QString(), QObject::tr("Failed to save.")); - } - }; - - if (fileState == Tracker::ScriptCanvasFileState::NEW) - { - SaveAssetAsImpl(fileAssetId, saveCB); - } - else - { - SaveAsset(fileAssetId, saveCB); - } + m_closeCurrentGraphAfterSave = true; + SaveAssetImpl(tabMetadata.m_assetId, fileState == Tracker::ScriptCanvasFileState::NEW ? Save::As : Save::InPlace); } else if (saveDialogResults == UnsavedChangesOptions::CONTINUE_WITHOUT_SAVING) { @@ -2862,16 +2559,15 @@ namespace ScriptCanvasEditor QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) { - auto assetId = tabdata.value(); - SaveAssetImpl(assetId, nullptr); + auto assetId = tabdata.value(); + SaveAssetImpl(assetId.m_assetId, Save::InPlace); } - } void MainWindow::CloseAllTabs() { m_isClosingTabs = true; - m_skipTabOnClose.SetInvalid(); + m_skipTabOnClose.Clear(); CloseNextTab(); } @@ -2881,7 +2577,7 @@ namespace ScriptCanvasEditor QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) { - auto assetId = tabdata.value(); + auto assetId = tabdata.value().m_assetId; m_isClosingTabs = true; m_skipTabOnClose = assetId; @@ -2897,14 +2593,10 @@ namespace ScriptCanvasEditor { QClipboard* clipBoard = QGuiApplication::clipboard(); - auto assetId = tabdata.value(); - - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); - - if (memoryAsset) + auto assetId = tabdata.value(); + if (!assetId.m_assetId.Path().empty()) { - clipBoard->setText(memoryAsset->GetAbsolutePath().c_str()); + clipBoard->setText(assetId.m_assetId.Path().c_str()); } else { @@ -2915,7 +2607,6 @@ namespace ScriptCanvasEditor void MainWindow::OnActiveFileStateChanged() { - UpdateSaveState(); UpdateAssignToSelectionState(); } @@ -2924,10 +2615,10 @@ namespace ScriptCanvasEditor if (m_isClosingTabs) { if (m_tabBar->count() == 0 - || (m_tabBar->count() == 1 && m_skipTabOnClose.IsValid())) + || (m_tabBar->count() == 1 && m_skipTabOnClose.IsGraphValid())) { m_isClosingTabs = false; - m_skipTabOnClose.SetInvalid(); + m_skipTabOnClose.Clear(); return; } @@ -2938,9 +2629,9 @@ namespace ScriptCanvasEditor QVariant tabdata = m_tabBar->tabData(tab); if (tabdata.isValid()) { - auto assetId = tabdata.value(); + auto assetId = tabdata.value(); - if (assetId != m_skipTabOnClose) + if (!assetId.m_assetId.AnyEquals(m_skipTabOnClose)) { break; } @@ -2958,26 +2649,27 @@ namespace ScriptCanvasEditor QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) { - auto tabAssetId = tabdata.value(); + auto tabAssetId = tabdata.value(); - if (tabAssetId == m_activeAssetId) + + if (tabAssetId.m_canvasWidget) { - SetActiveAsset({}); + tabAssetId.m_canvasWidget->hide(); } - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, tabAssetId); + bool activeSet = false; - if (memoryAsset && memoryAsset->GetView()) + if (tabAssetId.m_assetId.AnyEquals(m_activeGraph)) { - memoryAsset->GetView()->hide(); + SetActiveAsset({}); + activeSet = true; } m_tabBar->CloseTab(index); m_tabBar->update(); - RemoveScriptCanvasAsset(tabAssetId); + RemoveScriptCanvasAsset(tabAssetId.m_assetId); - if (m_tabBar->count() == 0) + if (!activeSet && m_tabBar->count() == 0) { // The last tab has been removed. SetActiveAsset({}); @@ -3164,7 +2856,7 @@ namespace ScriptCanvasEditor bool hasCopiableSelection = false; bool hasSelection = false; - if (m_activeAssetId.IsValid()) + if (m_activeGraph.IsGraphValid()) { if (graphCanvasGraphId.IsValid()) { @@ -3544,7 +3236,6 @@ namespace ScriptCanvasEditor UpdateAssignToSelectionState(); UpdateUndoRedoState(); - UpdateSaveState(); } void MainWindow::OnWorkspaceRestoreStart() @@ -3552,23 +3243,23 @@ namespace ScriptCanvasEditor m_isRestoringWorkspace = true; } - void MainWindow::OnWorkspaceRestoreEnd(AZ::Data::AssetId lastFocusAsset) + void MainWindow::OnWorkspaceRestoreEnd(ScriptCanvasEditor::SourceHandle lastFocusAsset) { if (m_isRestoringWorkspace) { m_isRestoringWorkspace = false; - if (m_queuedFocusOverride.IsValid()) + if (m_queuedFocusOverride.IsGraphValid()) { SetActiveAsset(m_queuedFocusOverride); - m_queuedFocusOverride.SetInvalid(); + m_queuedFocusOverride.Clear(); } - else if (lastFocusAsset.IsValid()) + else if (lastFocusAsset.IsGraphValid()) { SetActiveAsset(lastFocusAsset); } - if (!m_activeAssetId.IsValid()) + if (!m_activeGraph.IsGraphValid()) { if (m_tabBar->count() > 0) { @@ -3591,11 +3282,11 @@ namespace ScriptCanvasEditor void MainWindow::UpdateAssignToSelectionState() { - bool buttonEnabled = m_activeAssetId.IsValid(); + bool buttonEnabled = m_activeGraph.IsGraphValid(); if (buttonEnabled) { - const Tracker::ScriptCanvasFileState& fileState = GetAssetFileState(m_activeAssetId); + const Tracker::ScriptCanvasFileState& fileState = GetAssetFileState(m_activeGraph); if (fileState == Tracker::ScriptCanvasFileState::INVALID || fileState == Tracker::ScriptCanvasFileState::NEW || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED) { buttonEnabled = false; @@ -3622,24 +3313,10 @@ namespace ScriptCanvasEditor ui->action_Redo->setEnabled(isEnabled); } - void MainWindow::UpdateSaveState() + void MainWindow::UpdateSaveState(bool enabled) { - bool enabled = m_activeAssetId.IsValid(); - bool isSaving = false; - bool hasModifications = false; - - if (enabled) - { - Tracker::ScriptCanvasFileState fileState = GetAssetFileState(m_activeAssetId); - hasModifications = ( fileState == Tracker::ScriptCanvasFileState::MODIFIED - || fileState == Tracker::ScriptCanvasFileState::NEW - || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED); - - AssetTrackerRequestBus::BroadcastResult(isSaving, &AssetTrackerRequests::IsSaving, m_activeAssetId); - } - - ui->action_Save->setEnabled(enabled && !isSaving && hasModifications); - ui->action_Save_As->setEnabled(enabled && !isSaving); + ui->action_Save->setEnabled(enabled); + ui->action_Save_As->setEnabled(enabled); } void MainWindow::CreateFunctionInput() @@ -3837,21 +3514,24 @@ namespace ScriptCanvasEditor return findChild(elementName); } - AZ::EntityId MainWindow::FindEditorNodeIdByAssetNodeId(const AZ::Data::AssetId& assetId, AZ::EntityId assetNodeId) const + AZ::EntityId MainWindow::FindEditorNodeIdByAssetNodeId(const ScriptCanvasEditor::SourceHandle& assetId, AZ::EntityId assetNodeId) const { AZ::EntityId editorEntityId; - AssetTrackerRequestBus::BroadcastResult(editorEntityId, &AssetTrackerRequests::GetEditorEntityIdFromSceneEntityId, assetId, assetNodeId); + AssetTrackerRequestBus::BroadcastResult + ( editorEntityId, &AssetTrackerRequests::GetEditorEntityIdFromSceneEntityId, assetId.Id(), assetNodeId); return editorEntityId; } - AZ::EntityId MainWindow::FindAssetNodeIdByEditorNodeId(const AZ::Data::AssetId& assetId, AZ::EntityId editorNodeId) const + AZ::EntityId MainWindow::FindAssetNodeIdByEditorNodeId(const ScriptCanvasEditor::SourceHandle& assetId, AZ::EntityId editorNodeId) const { AZ::EntityId sceneEntityId; - AssetTrackerRequestBus::BroadcastResult(sceneEntityId, &AssetTrackerRequests::GetSceneEntityIdFromEditorEntityId, assetId, editorNodeId); + AssetTrackerRequestBus::BroadcastResult + ( sceneEntityId, &AssetTrackerRequests::GetSceneEntityIdFromEditorEntityId, assetId.Id(), editorNodeId); return sceneEntityId; } - GraphCanvas::Endpoint MainWindow::CreateNodeForProposalWithGroup(const AZ::EntityId& connectionId, const GraphCanvas::Endpoint& endpoint, const QPointF& scenePoint, const QPoint& screenPoint, AZ::EntityId groupTarget) + GraphCanvas::Endpoint MainWindow::CreateNodeForProposalWithGroup(const AZ::EntityId& connectionId + , const GraphCanvas::Endpoint& endpoint, const QPointF& scenePoint, const QPoint& screenPoint, AZ::EntityId groupTarget) { PushPreventUndoStateUpdate(); @@ -3961,7 +3641,7 @@ namespace ScriptCanvasEditor OnFileNew(); - if (m_activeAssetId.IsValid()) + if (m_activeGraph.IsGraphValid()) { graphId = GetActiveGraphCanvasGraphId(); } @@ -4225,12 +3905,6 @@ namespace ScriptCanvasEditor qobject_cast(parent())->close(); } - if (HasSystemTickAction(SystemTickActionFlag::UpdateSaveMenuState)) - { - RemoveSystemTickAction(SystemTickActionFlag::UpdateSaveMenuState); - UpdateSaveState(); - } - if (HasSystemTickAction(SystemTickActionFlag::CloseCurrentGraph)) { RemoveSystemTickAction(SystemTickActionFlag::CloseCurrentGraph); @@ -4247,10 +3921,7 @@ namespace ScriptCanvasEditor CloseNextTab(); } - if (m_systemTickActions == 0) - { - AZ::SystemTickBus::Handler::BusDisconnect(); - } + ClearStaleSaves(); } void MainWindow::OnCommandStarted(AZ::Crc32) @@ -4265,35 +3936,11 @@ namespace ScriptCanvasEditor void MainWindow::PrepareActiveAssetForSave() { - PrepareAssetForSave(m_activeAssetId); + PrepareAssetForSave(m_activeGraph); } - void MainWindow::PrepareAssetForSave(const AZ::Data::AssetId& assetId) + void MainWindow::PrepareAssetForSave(const ScriptCanvasEditor::SourceHandle& /*assetId*/) { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); - - if (memoryAsset) - { - AZ::EntityId graphId = memoryAsset->GetGraphId(); - AZ::EntityId scriptCanvasId = memoryAsset->GetScriptCanvasId(); - - AZ::Entity* entity = nullptr; - GraphRequestBus::EventResult(entity, scriptCanvasId, &GraphRequests::GetGraphEntity); - - if (entity) - { - GraphCanvas::GraphModelRequestBus::Event(graphId, &GraphCanvas::GraphModelRequests::OnSaveDataDirtied, entity->GetId()); - } - - GraphCanvas::GraphModelRequestBus::Event(graphId, &GraphCanvas::GraphModelRequests::OnSaveDataDirtied, graphId); - - ScriptCanvasEditor::Graph* graph = AZ::EntityUtils::FindFirstDerivedComponent(entity); - if (graph) - { - graph->MarkVersion(); - } - } } void MainWindow::RestartAutoTimerSave(bool forceTimer) @@ -4336,39 +3983,38 @@ namespace ScriptCanvasEditor void MainWindow::OnAssignToSelectedEntities() { - Tracker::ScriptCanvasFileState fileState; - AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, m_activeAssetId); - + Tracker::ScriptCanvasFileState fileState = GetAssetFileState(m_activeGraph);; + bool isDocumentOpen = false; AzToolsFramework::EditorRequests::Bus::BroadcastResult(isDocumentOpen, &AzToolsFramework::EditorRequests::IsLevelDocumentOpen); - + if (fileState == Tracker::ScriptCanvasFileState::NEW || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED || !isDocumentOpen) { return; } - + AzToolsFramework::EntityIdList selectedEntityIds; AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(selectedEntityIds, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities); - + auto selectedEntityIdIter = selectedEntityIds.begin(); - + bool isLayerAmbiguous = false; AZ::EntityId targetLayer; - + while (selectedEntityIdIter != selectedEntityIds.end()) { bool isLayerEntity = false; AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(isLayerEntity, (*selectedEntityIdIter), &AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer); - + if (isLayerEntity) { if (targetLayer.IsValid()) { isLayerAmbiguous = true; } - + targetLayer = (*selectedEntityIdIter); - + selectedEntityIdIter = selectedEntityIds.erase(selectedEntityIdIter); } else @@ -4376,20 +4022,20 @@ namespace ScriptCanvasEditor ++selectedEntityIdIter; } } - + if (selectedEntityIds.empty()) { AZ::EntityId createdId; AzToolsFramework::EditorRequests::Bus::BroadcastResult(createdId, &AzToolsFramework::EditorRequests::CreateNewEntity, AZ::EntityId()); - + selectedEntityIds.emplace_back(createdId); - + if (targetLayer.IsValid() && !isLayerAmbiguous) { AZ::TransformBus::Event(createdId, &AZ::TransformBus::Events::SetParent, targetLayer); } } - + for (const AZ::EntityId& entityId : selectedEntityIds) { AssignGraphToEntityImpl(entityId); @@ -4398,7 +4044,7 @@ namespace ScriptCanvasEditor void MainWindow::OnAssignToEntity(const AZ::EntityId& entityId) { - Tracker::ScriptCanvasFileState fileState = GetAssetFileState(m_activeAssetId); + Tracker::ScriptCanvasFileState fileState = GetAssetFileState(m_activeGraph); if (fileState == Tracker::ScriptCanvasFileState::MODIFIED || fileState == Tracker::ScriptCanvasFileState::UNMODIFIED) @@ -4407,11 +4053,10 @@ namespace ScriptCanvasEditor } } - ScriptCanvasEditor::Tracker::ScriptCanvasFileState MainWindow::GetAssetFileState(AZ::Data::AssetId assetId) const + ScriptCanvasEditor::Tracker::ScriptCanvasFileState MainWindow::GetAssetFileState(ScriptCanvasEditor::SourceHandle assetId) const { - Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::INVALID; - AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, assetId); - return fileState; + auto dataOptional = m_tabBar->GetTabData(assetId); + return dataOptional ? dataOptional->m_fileState : Tracker::ScriptCanvasFileState::INVALID; } void MainWindow::AssignGraphToEntityImpl(const AZ::EntityId& entityId) @@ -4459,14 +4104,7 @@ namespace ScriptCanvasEditor if (usableRequestBus) { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeAssetId); - - if (memoryAsset) - { - // We need to assign the AssetId for the file asset, not the in-memory asset - usableRequestBus->SetAssetId(memoryAsset->GetFileAssetId()); - } + usableRequestBus->SetAssetId(m_activeGraph.Describe()); } } @@ -4482,11 +4120,6 @@ namespace ScriptCanvasEditor void MainWindow::AddSystemTickAction(SystemTickActionFlag action) { - if (!AZ::SystemTickBus::Handler::BusIsConnected()) - { - AZ::SystemTickBus::Handler::BusConnect(); - } - m_systemTickActions |= action; } @@ -4516,6 +4149,7 @@ namespace ScriptCanvasEditor m_filesToOpen.pop_front(); OpenFile(nextFile.toUtf8().data()); + OpenNextFile(); } else { @@ -4789,11 +4423,11 @@ namespace ScriptCanvasEditor //connect(m_unitTestDockWidget, &QDockWidget::visibilityChanged, this, &MainWindow::OnViewVisibilityChanged); } - void MainWindow::DisableAssetView(ScriptCanvasMemoryAsset::pointer memoryAsset) + void MainWindow::DisableAssetView(const ScriptCanvasEditor::SourceHandle& memoryAssetId) { - if (memoryAsset->GetView()) + if (auto view = m_tabBar->ModTabView(m_tabBar->FindTab(memoryAssetId))) { - memoryAsset->GetView()->DisableView(); + view->DisableView(); } m_tabBar->setEnabled(false); @@ -4813,11 +4447,11 @@ namespace ScriptCanvasEditor m_autoSaveTimer.stop(); } - void MainWindow::EnableAssetView(ScriptCanvasMemoryAsset::pointer memoryAsset) + void MainWindow::EnableAssetView(const ScriptCanvasEditor::SourceHandle& memoryAssetId) { - if (memoryAsset->GetView()) + if (auto view = m_tabBar->ModTabView(m_tabBar->FindTab(memoryAssetId))) { - memoryAsset->GetView()->EnableView(); + view->EnableView(); } m_tabBar->setEnabled(true); @@ -4835,5 +4469,34 @@ namespace ScriptCanvasEditor UpdateUndoRedoState(); } + + void MainWindow::ClearStaleSaves() + { + AZStd::lock_guard lock(m_mutex); + auto timeNow = AZStd::chrono::system_clock::now(); + AZStd::erase_if(m_saves, [&timeNow](const auto& item) + { + AZStd::sys_time_t delta = AZStd::chrono::seconds(timeNow - item.second).count(); + return delta > 2.0f; + }); + } + + bool MainWindow::IsRecentSave(const SourceHandle& handle) const + { + AZStd::lock_guard lock(const_cast(this)->m_mutex); + AZStd::string key = handle.Path().Native(); + AZStd::to_lower(key.begin(), key.end()); + auto iter = m_saves.find(key); + return iter != m_saves.end(); + } + + void MainWindow::MarkRecentSave(const SourceHandle& handle) + { + AZStd::lock_guard lock(m_mutex); + AZStd::string key = handle.Path().Native(); + AZStd::to_lower(key.begin(), key.end()); + m_saves[key] = AZStd::chrono::system_clock::now(); + } + #include } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h index 7672f0a199..28e9cab948 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h @@ -43,7 +43,6 @@ #include #include #include - #include #include #include @@ -51,8 +50,8 @@ #include #include - #include +#include #if SCRIPTCANVAS_EDITOR #include @@ -153,7 +152,7 @@ namespace ScriptCanvasEditor } }; - //! Manages the Save/Restore operations of the user's las topened and focused graphs + //! Manages the Save/Restore operations of the user's last opened and focused graphs class Workspace : AssetTrackerNotificationBus::MultiHandler { @@ -175,9 +174,9 @@ namespace ScriptCanvasEditor private: void OnAssetReady(const ScriptCanvasMemoryAsset::pointer asset) override; - void SignalAssetComplete(const AZ::Data::AssetId& fileAssetId); + void SignalAssetComplete(const ScriptCanvasEditor::SourceHandle& fileAssetId); - AZ::Data::AssetId GetSourceAssetId(const AZ::Data::AssetId& memoryAssetId) const; + ScriptCanvasEditor::SourceHandle GetSourceAssetId(const ScriptCanvasEditor::SourceHandle& memoryAssetId) const; bool m_rememberOpenCanvases; MainWindow* m_mainWindow; @@ -185,10 +184,10 @@ namespace ScriptCanvasEditor //! Setting focus is problematic unless it is done until after all currently loading graphs have finished loading //! This vector is used to track the list of graphs being opened to restore the workspace and as assets are fully //! ready and activated they are removed from this list. - AZStd::vector m_loadingAssets; + AZStd::vector m_loadingAssets; //! During restore we queue the asset Id to focus in order to do it last - AZ::Data::AssetId m_queuedAssetFocus; + ScriptCanvasEditor::SourceHandle m_queuedAssetFocus; }; enum class UnsavedChangesOptions; @@ -230,7 +229,6 @@ namespace ScriptCanvasEditor , private VariablePaletteRequestBus::Handler , private ScriptCanvas::BatchOperationNotificationBus::Handler , private AssetGraphSceneBus::Handler - , private AssetTrackerNotificationBus::MultiHandler #if SCRIPTCANVAS_EDITOR //, public IEditorNotifyListener #endif @@ -239,6 +237,7 @@ namespace ScriptCanvasEditor , private GraphCanvas::ViewNotificationBus::Handler , public AZ::SystemTickBus::Handler , private AzToolsFramework::ToolsApplicationNotificationBus::Handler + , private AzToolsFramework::AssetSystemBus::Handler , private ScriptCanvas::ScriptCanvasSettingsRequestBus::Handler { Q_OBJECT @@ -269,7 +268,7 @@ namespace ScriptCanvasEditor // Undo Handlers void PostUndoPoint(ScriptCanvas::ScriptCanvasId scriptCanvasId) override; - void SignalSceneDirty(AZ::Data::AssetId assetId) override; + void SignalSceneDirty(ScriptCanvasEditor::SourceHandle assetId) override; void PushPreventUndoStateUpdate() override; void PopPreventUndoStateUpdate() override; @@ -325,12 +324,17 @@ namespace ScriptCanvasEditor // File menu void OnFileNew(); - bool OnFileSave(const Callbacks::OnSave& saveCB); - bool OnFileSaveAs(const Callbacks::OnSave& saveCB); - bool OnFileSaveCaller(){return OnFileSave(nullptr);}; - bool OnFileSaveAsCaller(){return OnFileSaveAs(nullptr);}; - bool SaveAssetImpl(const AZ::Data::AssetId& assetId, const Callbacks::OnSave& saveCB); - bool SaveAssetAsImpl(const AZ::Data::AssetId& assetId, const Callbacks::OnSave& saveCB); + bool OnFileSave(); + bool OnFileSaveAs(); + bool OnFileSaveCaller(){return OnFileSave();}; + bool OnFileSaveAsCaller(){return OnFileSaveAs();}; + bool SaveAssetImpl_OLD(const ScriptCanvasEditor::SourceHandle& assetId, const Callbacks::OnSave& saveCB); + enum class Save + { + InPlace, + As + }; + bool SaveAssetImpl(const ScriptCanvasEditor::SourceHandle& assetId, Save save); void OnFileOpen(); // Edit menu @@ -415,30 +419,27 @@ namespace ScriptCanvasEditor void CloseNextTab(); - bool IsTabOpen(const AZ::Data::AssetId& assetId, int& outTabIndex) const; - QVariant GetTabData(const AZ::Data::AssetId& assetId); + bool IsTabOpen(const SourceHandle& assetId, int& outTabIndex) const; + QVariant GetTabData(const SourceHandle& assetId); //! GeneralRequestBus - AZ::Outcome OpenScriptCanvasAssetId(const AZ::Data::AssetId& assetId) override; - AZ::Outcome OpenScriptCanvasAsset(AZ::Data::AssetId scriptCanvasAssetId, int tabIndex = -1) override; - AZ::Outcome OpenScriptCanvasAsset(const ScriptCanvasMemoryAsset& scriptCanvasAsset, int tabIndex = -1); - int CloseScriptCanvasAsset(const AZ::Data::AssetId& assetId) override; + AZ::Outcome OpenScriptCanvasAssetId(const SourceHandle& assetId, Tracker::ScriptCanvasFileState fileState) override; + AZ::Outcome OpenScriptCanvasAsset(SourceHandle scriptCanvasAssetId, Tracker::ScriptCanvasFileState fileState, int tabIndex = -1) override; + AZ::Outcome OpenScriptCanvasAssetImplementation(const SourceHandle& sourceHandle, Tracker::ScriptCanvasFileState fileState, int tabIndex = -1); + int CloseScriptCanvasAsset(const SourceHandle& assetId) override; bool CreateScriptCanvasAssetFor(const TypeDefs::EntityComponentId& requestingEntityId) override; - bool IsScriptCanvasAssetOpen(const AZ::Data::AssetId& assetId) const override; + bool IsScriptCanvasAssetOpen(const SourceHandle& assetId) const override; const CategoryInformation* FindNodePaletteCategoryInformation(AZStd::string_view categoryPath) const override; const NodePaletteModelInformation* FindNodePaletteModelInformation(const ScriptCanvas::NodeTypeIdentifier& nodeType) const override; //// - AZ::Outcome CreateScriptCanvasAsset(AZStd::string_view assetPath, AZ::Data::AssetType assetType, int tabIndex = -1); - AZ::Outcome UpdateScriptCanvasAsset(const AZ::Data::Asset& scriptCanvasAsset); + AZ::Outcome CreateScriptCanvasAsset(AZStd::string_view assetPath, int tabIndex = -1); - void RefreshScriptCanvasAsset(const AZ::Data::Asset& scriptCanvasAsset); - //! Removes the assetId -> ScriptCanvasAsset mapping and disconnects from the asset tracker - void RemoveScriptCanvasAsset(const AZ::Data::AssetId& assetId); - void OnChangeActiveGraphTab(AZ::Data::AssetId) override; + void RemoveScriptCanvasAsset(const ScriptCanvasEditor::SourceHandle& assetId); + void OnChangeActiveGraphTab(ScriptCanvasEditor::SourceHandle) override; void CreateNewRuntimeAsset() override { OnFileNew(); } @@ -448,8 +449,8 @@ namespace ScriptCanvasEditor GraphCanvas::GraphId GetGraphCanvasGraphId(const ScriptCanvas::ScriptCanvasId& scriptCanvasId) const override; - GraphCanvas::GraphId FindGraphCanvasGraphIdByAssetId(const AZ::Data::AssetId& assetId) const override; - ScriptCanvas::ScriptCanvasId FindScriptCanvasIdByAssetId(const AZ::Data::AssetId& assetId) const override; + GraphCanvas::GraphId FindGraphCanvasGraphIdByAssetId(const ScriptCanvasEditor::SourceHandle& assetId) const override; + ScriptCanvas::ScriptCanvasId FindScriptCanvasIdByAssetId(const ScriptCanvasEditor::SourceHandle& assetId) const override; bool IsInUndoRedo(const AZ::EntityId& graphCanvasGraphId) const override; bool IsScriptCanvasInUndoRedo(const ScriptCanvas::ScriptCanvasId& scriptCanvasId) const override; @@ -517,17 +518,18 @@ namespace ScriptCanvasEditor QObject* FindElementByName(QString elementName) override; //// - AZ::EntityId FindEditorNodeIdByAssetNodeId(const AZ::Data::AssetId& assetId, AZ::EntityId assetNodeId) const override; - AZ::EntityId FindAssetNodeIdByEditorNodeId(const AZ::Data::AssetId& assetId, AZ::EntityId editorNodeId) const override; + AZ::EntityId FindEditorNodeIdByAssetNodeId(const ScriptCanvasEditor::SourceHandle& assetId, AZ::EntityId assetNodeId) const override; + AZ::EntityId FindAssetNodeIdByEditorNodeId(const ScriptCanvasEditor::SourceHandle& assetId, AZ::EntityId editorNodeId) const override; private: + void SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid fileAssetId) override; + void SourceFileRemoved(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid fileAssetId) override; + void DeleteNodes(const AZ::EntityId& sceneId, const AZStd::vector& nodes) override; void DeleteConnections(const AZ::EntityId& sceneId, const AZStd::vector& connections) override; void DisconnectEndpoints(const AZ::EntityId& sceneId, const AZStd::vector& endpoints) override; ///////////////////////////////////////////////////////////////////////////////////////////// - void UpdateWorkspaceStatus(const ScriptCanvasMemoryAsset& scriptCanvasAsset); - GraphCanvas::Endpoint HandleProposedConnection(const GraphCanvas::GraphId& graphId, const GraphCanvas::ConnectionId& connectionId, const GraphCanvas::Endpoint& endpoint, const GraphCanvas::NodeId& proposedNode, const QPoint& screenPoint); //! UndoNotificationBus @@ -543,29 +545,20 @@ namespace ScriptCanvasEditor void OnAutoSave(); - //! Helper function which serializes a file to disk - //! \param filename name of file to serialize the Entity - //! \param asset asset to save - void GetSuggestedFullFilenameToSaveAs(const AZ::Data::AssetId& assetId, AZStd::string& filePath, AZStd::string& fileFilter); - - void MarkAssetModified(const AZ::Data::AssetId& assetId); + void UpdateFileState(const ScriptCanvasEditor::SourceHandle& assetId, Tracker::ScriptCanvasFileState fileState); // QMainWindow void closeEvent(QCloseEvent *event) override; UnsavedChangesOptions ShowSaveDialog(const QString& filename); - bool ActivateAndSaveAsset(const AZ::Data::AssetId& unsavedAssetId, const Callbacks::OnSave& onSave); + bool ActivateAndSaveAsset(const ScriptCanvasEditor::SourceHandle& unsavedAssetId); - void SaveNewAsset(AZStd::string_view path, AZ::Data::AssetId assetId, const Callbacks::OnSave& onSave); - void SaveAsset(AZ::Data::AssetId assetId, const Callbacks::OnSave& onSave); + void SaveAs(AZStd::string_view path, ScriptCanvasEditor::SourceHandle assetId); void OpenFile(const char* fullPath); void CreateMenus(); - void SignalActiveSceneChanged(const AZ::Data::AssetId assetId); - - void SaveWorkspace(bool updateAssetList = true); - void RestoreWorkspace(); + void SignalActiveSceneChanged(const ScriptCanvasEditor::SourceHandle assetId); void RunUpgradeTool(); @@ -593,29 +586,27 @@ namespace ScriptCanvasEditor void UpdateMenuState(bool enabledState); void OnWorkspaceRestoreStart(); - void OnWorkspaceRestoreEnd(AZ::Data::AssetId lastFocusAsset); + void OnWorkspaceRestoreEnd(ScriptCanvasEditor::SourceHandle lastFocusAsset); void UpdateAssignToSelectionState(); void UpdateUndoRedoState(); - void UpdateSaveState(); + void UpdateSaveState(bool enabled); void CreateFunctionInput(); void CreateFunctionOutput(); void CreateFunctionDefinitionNode(int positionOffset); - int CreateAssetTab(const AZ::Data::AssetId& assetId, int tabIndex = -1); + int CreateAssetTab(const ScriptCanvasEditor::SourceHandle& assetId, Tracker::ScriptCanvasFileState fileState, int tabIndex = -1); //! \param asset The AssetId of the ScriptCanvas Asset. - void SetActiveAsset(const AZ::Data::AssetId& assetId); + void SetActiveAsset(const ScriptCanvasEditor::SourceHandle& assetId); void RefreshActiveAsset(); - void ReconnectSceneBuses(AZ::Data::AssetId previousAssetId, AZ::Data::AssetId nextAssetId); - - void SignalBatchOperationComplete(BatchOperatorTool* batchTool); + void ReconnectSceneBuses(ScriptCanvasEditor::SourceHandle previousAssetId, ScriptCanvasEditor::SourceHandle nextAssetId); void PrepareActiveAssetForSave(); - void PrepareAssetForSave(const AZ::Data::AssetId& asssetId); + void PrepareAssetForSave(const ScriptCanvasEditor::SourceHandle& asssetId); void RestartAutoTimerSave(bool forceTimer = false); @@ -626,24 +617,16 @@ namespace ScriptCanvasEditor void AssignGraphToEntityImpl(const AZ::EntityId& entityId); //// - Tracker::ScriptCanvasFileState GetAssetFileState(AZ::Data::AssetId assetId) const; + Tracker::ScriptCanvasFileState GetAssetFileState(ScriptCanvasEditor::SourceHandle assetId) const; - AZ::Data::AssetId GetSourceAssetId(const AZ::Data::AssetId& memoryAssetId) const + ScriptCanvasEditor::SourceHandle GetSourceAssetId(const ScriptCanvasEditor::SourceHandle& memoryAssetId) const { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, memoryAssetId); - - if (memoryAsset) - { - return memoryAsset->GetFileAssetId(); - } - - return AZ::Data::AssetId(); + return memoryAssetId; } - int InsertTabForAsset(AZStd::string_view assetPath, AZ::Data::AssetId assetId, int tabIndex = -1); + int InsertTabForAsset(AZStd::string_view assetPath, ScriptCanvasEditor::SourceHandle assetId, int tabIndex = -1); - void UpdateUndoCache(AZ::Data::AssetId assetId); + void UpdateUndoCache(ScriptCanvasEditor::SourceHandle assetId); bool HasSystemTickAction(SystemTickActionFlag action); @@ -655,34 +638,9 @@ namespace ScriptCanvasEditor void OpenNextFile(); - template - void MakeNewFile() - { - static int scriptCanvasEditorDefaultNewNameCount = 0; - AZStd::string newAssetName = AZStd::string::format(ScriptCanvas::AssetDescription::GetAssetNamePattern(), ++scriptCanvasEditorDefaultNewNameCount); - - AZStd::array assetRootArray; - if (!AZ::IO::FileIOBase::GetInstance()->ResolvePath(ScriptCanvas::AssetDescription::GetSuggestedSavePath(), assetRootArray.data(), assetRootArray.size())) - { - AZ_ErrorOnce("Script Canvas", false, "Unable to resolve @projectroot@ path"); - } - - AZStd::string assetPath; - AzFramework::StringFunc::Path::Join(assetRootArray.data(), (newAssetName + ScriptCanvas::AssetDescription::GetExtension()).data(), assetPath); - - auto createOutcome = CreateScriptCanvasAsset(assetPath, azrtti_typeid()); - if (createOutcome) - { - } - else - { - AZ_Warning("Script Canvas", createOutcome, "%s", createOutcome.GetError().data()); - } - } - - void DisableAssetView(ScriptCanvasMemoryAsset::pointer memoryAsset); - void EnableAssetView(ScriptCanvasMemoryAsset::pointer memoryAsset); + void DisableAssetView(const ScriptCanvasEditor::SourceHandle& memoryAssetId); + void EnableAssetView(const ScriptCanvasEditor::SourceHandle& memoryAssetId); QWidget* m_host = nullptr; @@ -741,22 +699,22 @@ namespace ScriptCanvasEditor GraphCanvas::GraphCanvasEditorEmptyDockWidget* m_emptyCanvas; // Displayed when there is no open graph QVBoxLayout* m_layout; - AZ::Data::AssetId m_activeAssetId; - + ScriptCanvasEditor::SourceHandle m_activeGraph; + bool m_loadingNewlySavedFile; AZStd::string m_newlySavedFile; AZStd::string m_errorFilePath; bool m_isClosingTabs; - AZ::Data::AssetId m_skipTabOnClose; + ScriptCanvasEditor::SourceHandle m_skipTabOnClose; bool m_enterState; bool m_ignoreSelection; AZ::s32 m_preventUndoStateUpdateCount; bool m_isRestoringWorkspace; - AZ::Data::AssetId m_queuedFocusOverride; + ScriptCanvasEditor::SourceHandle m_queuedFocusOverride; Ui::MainWindow* ui; AZStd::array, c_scriptCanvasEditorSettingsRecentFilesCountMax> m_recentActions; @@ -778,17 +736,17 @@ namespace ScriptCanvasEditor AZStd::vector m_selectedVariableIds; AZ::u32 m_systemTickActions; - AZStd::unordered_set< AZ::Data::AssetId > m_processedClosedAssetIds; + AZStd::unordered_set< ScriptCanvasEditor::SourceHandle > m_processedClosedAssetIds; - AZStd::unordered_set< AZ::Data::AssetId > m_loadingWorkspaceAssets; - AZStd::unordered_set< AZ::Data::AssetId > m_loadingAssets; + AZStd::unordered_set< ScriptCanvasEditor::SourceHandle > m_loadingWorkspaceAssets; + AZStd::unordered_set< ScriptCanvasEditor::SourceHandle > m_loadingAssets; AZStd::unordered_set< AZ::Uuid > m_variablePaletteTypes; AZStd::unordered_map< AZ::Crc32, QObject* > m_automationLookUpMap; bool m_closeCurrentGraphAfterSave; - AZStd::unordered_map< AZ::Data::AssetId, TypeDefs::EntityComponentId > m_assetCreationRequests; + AZStd::unordered_map< ScriptCanvasEditor::SourceHandle, TypeDefs::EntityComponentId > m_assetCreationRequests; ScriptCanvas::Debugger::ClientTransceiver m_clientTRX; GraphCanvas::StyleManager m_styleManager; @@ -797,6 +755,14 @@ namespace ScriptCanvasEditor //! this object manages the Save/Restore operations Workspace* m_workspace; - void OnSaveCallback(bool saveSuccess, AZ::Data::AssetPtr, AZ::Data::AssetId previousFileAssetId); + AZStd::unique_ptr m_fileSaver; + VersionExplorer::FileSaveResult m_fileSaveResult; + void OnSaveCallBack(const VersionExplorer::FileSaveResult& result); + + void ClearStaleSaves(); + bool IsRecentSave(const SourceHandle& handle) const; + void MarkRecentSave(const SourceHandle& handle); + AZStd::recursive_mutex m_mutex; + AZStd::unordered_map m_saves; }; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp index dbcd176ee5..b666ef32f5 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp @@ -53,7 +53,6 @@ namespace ScriptCanvasEditor m_view->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); connect(m_view->scanButton, &QPushButton::pressed, this, &Controller::OnButtonPressScan); connect(m_view->closeButton, &QPushButton::pressed, this, &Controller::OnButtonPressClose); - m_view->upgradeAllButton->setVisible(false); connect(m_view->upgradeAllButton, &QPushButton::pressed, this, &Controller::OnButtonPressUpgrade); m_view->progressBar->setValue(0); m_view->progressBar->setVisible(false); @@ -104,9 +103,9 @@ namespace ScriptCanvasEditor } } - QList Controller::FindTableItems(const AZ::Data::AssetInfo& info) + QList Controller::FindTableItems(const SourceHandle& info) { - return m_view->tableWidget->findItems(info.m_relativePath.c_str(), Qt::MatchFlag::MatchExactly); + return m_view->tableWidget->findItems(info.Path().c_str(), Qt::MatchFlag::MatchExactly); } void Controller::OnButtonPressClose() @@ -117,30 +116,20 @@ namespace ScriptCanvasEditor void Controller::OnButtonPressScan() { // \todo move to another file - auto isUpToDate = [this](AZ::Data::Asset asset) + auto isUpToDate = [this](const SourceHandle& asset) { - AZ::Entity* scriptCanvasEntity = nullptr; + auto graphComponent = asset.Get(); - if (asset.GetType() == azrtti_typeid()) - { - ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); - if (!scriptCanvasAsset) - { - AZ_Warning - (ScriptCanvas::k_VersionExplorerWindow.data() - , false - , "InspectAsset: %s, AsestData failed to return ScriptCanvasAsset" - , asset.GetHint().c_str()); - return true; - } + AZ_Warning + ( ScriptCanvas::k_VersionExplorerWindow.data() + , asset.Get() != nullptr + , "InspectAsset: %s, failed to load valid graph" + , asset.Path().c_str()); - scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "The Script Canvas asset must have a valid entity"); - } - - auto graphComponent = scriptCanvasEntity->FindComponent(); - AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); - return !m_view->forceUpgrade->isChecked() && graphComponent->GetVersion().IsLatest(); + return graphComponent + && (!graphComponent->GetVersion().IsLatest() || m_view->forceUpgrade->isChecked()) + ? ScanConfiguration::Filter::Include + : ScanConfiguration::Filter::Exclude; }; ScanConfiguration config; @@ -156,59 +145,19 @@ namespace ScriptCanvasEditor OnButtonPressUpgradeImplementation({}); } - void Controller::OnButtonPressUpgradeImplementation(const AZ::Data::AssetInfo& assetInfo) + void Controller::OnButtonPressUpgradeImplementation(const SourceHandle& assetInfo) { - auto simpleUpdate = [this](AZ::Data::Asset asset) + auto simpleUpdate = [this](SourceHandle& asset) { - if (asset.GetType() == azrtti_typeid()) + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), asset.Get() != nullptr + , "The Script Canvas asset must have a Graph component"); + + if (asset.Get()) { - ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); - AZ_Assert(scriptCanvasAsset, "Unable to get the asset of ScriptCanvasAsset, but received type: %s" - , azrtti_typeid().template ToString().c_str()); - if (!scriptCanvasAsset) - { - return; - } - - AZ::Entity* scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "View::UpgradeGraph The Script Canvas asset must have a valid entity"); - if (!scriptCanvasEntity) - { - return; - } - - AZ::Entity* queryEntity = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(queryEntity, &AZ::ComponentApplicationRequests::FindEntity, scriptCanvasEntity->GetId()); - if (queryEntity) - { - if (queryEntity->GetState() == AZ::Entity::State::Active) - { - queryEntity->Deactivate(); - } - - scriptCanvasEntity = queryEntity; - } - - if (scriptCanvasEntity->GetState() == AZ::Entity::State::Constructed) - { - scriptCanvasEntity->Init(); - } - - if (scriptCanvasEntity->GetState() == AZ::Entity::State::Init) - { - scriptCanvasEntity->Activate(); - } - - AZ_Assert(scriptCanvasEntity->GetState() == AZ::Entity::State::Active, "Graph entity is not active"); - auto graphComponent = scriptCanvasEntity->FindComponent(); - AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); - if (graphComponent) - { - graphComponent->UpgradeGraph - (asset - , m_view->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate - , m_view->verbose->isChecked()); - } + asset.Mod()->UpgradeGraph + ( asset + , m_view->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate + , m_view->verbose->isChecked()); } }; @@ -216,7 +165,7 @@ namespace ScriptCanvasEditor { int result = QMessageBox::No; QMessageBox mb - (QMessageBox::Warning + ( QMessageBox::Warning , QObject::tr("Failed to Save Upgraded File") , QObject::tr("The upgraded file could not be saved because the file is read only.\n" "Do you want to make it writeable and overwrite it?") @@ -235,12 +184,17 @@ namespace ScriptCanvasEditor ModelRequestsBus::Broadcast(&ModelRequestsTraits::Modify, config); } - void Controller::OnButtonPressUpgradeSingle(const AZ::Data::AssetInfo& assetInfo) + void Controller::OnButtonPressUpgradeSingle(const SourceHandle& info) { - OnButtonPressUpgradeImplementation(assetInfo); + OnButtonPressUpgradeImplementation(info); } - void Controller::OnUpgradeModificationBegin([[maybe_unused]] const ModifyConfiguration& config, const AZ::Data::AssetInfo& info) + void Controller::OnUpgradeDependencyWaitInterval([[maybe_unused]] const SourceHandle& info) + { + AddLogEntries(); + } + + void Controller::OnUpgradeModificationBegin([[maybe_unused]] const ModifyConfiguration& config, const SourceHandle& info) { for (auto* item : FindTableItems(info)) { @@ -252,16 +206,18 @@ namespace ScriptCanvasEditor void Controller::OnUpgradeModificationEnd ( [[maybe_unused]] const ModifyConfiguration& config - , const AZ::Data::AssetInfo& info + , const SourceHandle& info , ModificationResult result) { if (result.errorMessage.empty()) { - VE_LOG("Successfully modified %s", result.assetInfo.m_relativePath.c_str()); + VE_LOG("Successfully modified %s", result.asset.Path().c_str()); } else { - VE_LOG("Failed to modify %s: %s", result.assetInfo.m_relativePath.c_str(), result.errorMessage.data()); + VE_LOG("Failed to modify %s: %s", result.asset.Path().c_str(), result.errorMessage.data()); + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data() + , false, "Failed to modify %s: %s", result.asset.Path().c_str(), result.errorMessage.data()); } for (auto* item : FindTableItems(info)) @@ -289,12 +245,10 @@ namespace ScriptCanvasEditor AddLogEntries(); } - void Controller::OnGraphUpgradeComplete(AZ::Data::Asset& asset, bool skipped) + void Controller::OnGraphUpgradeComplete(ScriptCanvasEditor::SourceHandle& asset, bool skipped) { ModificationResult result; result.asset = asset; - AZ::Data::AssetCatalogRequestBus::BroadcastResult - ( result.assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, asset.GetId()); if (skipped) { @@ -342,19 +296,19 @@ namespace ScriptCanvasEditor } } - void Controller::OnScanFilteredGraph(const AZ::Data::AssetInfo& info) + void Controller::OnScanFilteredGraph(const SourceHandle& info) { OnScannedGraph(info, Filtered::Yes); } - void Controller::OnScannedGraph(const AZ::Data::AssetInfo& assetInfo, [[maybe_unused]] Filtered filtered) + void Controller::OnScannedGraph(const SourceHandle& assetInfo, [[maybe_unused]] Filtered filtered) { const int rowIndex = m_view->tableWidget->rowCount(); if (filtered == Filtered::No || !m_view->onlyShowOutdated->isChecked()) { m_view->tableWidget->insertRow(rowIndex); - QTableWidgetItem* rowName = new QTableWidgetItem(tr(assetInfo.m_relativePath.c_str())); + QTableWidgetItem* rowName = new QTableWidgetItem(tr(assetInfo.Path().c_str())); m_view->tableWidget->setItem(rowIndex, static_cast(ColumnAsset), rowName); SetRowSucceeded(rowIndex); @@ -376,17 +330,11 @@ namespace ScriptCanvasEditor m_view->tableWidget->setCellWidget(rowIndex, static_cast(ColumnAction), upgradeButton); } - - char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; - AZStd::string path = AZStd::string::format("@devroot@/%s", assetInfo.m_relativePath.c_str()); - AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); - AZ::StringFunc::Path::GetFullPath(resolvedBuffer, path); - AZ::StringFunc::Path::Normalize(path); - + bool result = false; AZ::Data::AssetInfo info; AZStd::string watchFolder; - QByteArray assetNameUtf8 = assetInfo.m_relativePath.c_str(); + QByteArray assetNameUtf8 = assetInfo.Path().c_str(); AzToolsFramework::AssetSystemRequestBus::BroadcastResult ( result , &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath @@ -413,41 +361,41 @@ namespace ScriptCanvasEditor OnScannedGraphResult(assetInfo); } - void Controller::OnScannedGraphResult([[maybe_unused]] const AZ::Data::AssetInfo& info) + void Controller::OnScannedGraphResult([[maybe_unused]] const SourceHandle& info) { m_view->progressBar->setValue(aznumeric_cast(m_handledAssetCount)); ++m_handledAssetCount; AddLogEntries(); } - void Controller::OnScanLoadFailure(const AZ::Data::AssetInfo& info) + void Controller::OnScanLoadFailure(const SourceHandle& info) { const int rowIndex = m_view->tableWidget->rowCount(); m_view->tableWidget->insertRow(rowIndex); QTableWidgetItem* rowName = new QTableWidgetItem - ( tr(AZStd::string::format("Load Error: %s", info.m_relativePath.c_str()).c_str())); + ( tr(AZStd::string::format("Load Error: %s", info.Path().c_str()).c_str())); m_view->tableWidget->setItem(rowIndex, static_cast(ColumnAsset), rowName); SetRowFailed(rowIndex, "Load failed"); OnScannedGraphResult(info); } - void Controller::OnScanUnFilteredGraph(const AZ::Data::AssetInfo& info) + void Controller::OnScanUnFilteredGraph(const SourceHandle& info) { OnScannedGraph(info, Filtered::No); } void Controller::OnUpgradeBegin ( const ModifyConfiguration& config - , [[maybe_unused]] const WorkingAssets& assets) + , [[maybe_unused]] const AZStd::vector& assets) { QString spinnerText = QStringLiteral("Upgrade in progress - "); - if (config.modifySingleAsset.m_assetId.IsValid()) + if (!config.modifySingleAsset.Path().empty()) { spinnerText.append(" single graph"); if (assets.size() == 1) { - for (auto* item : FindTableItems(assets.front().info)) + for (auto* item : FindTableItems(assets.front())) { int row = item->row(); SetRowBusy(row); @@ -498,7 +446,7 @@ namespace ScriptCanvasEditor m_view->scanButton->setEnabled(true); } - void Controller::OnUpgradeDependenciesGathered(const AZ::Data::AssetInfo& info, Result result) + void Controller::OnUpgradeDependenciesGathered(const SourceHandle& info, Result result) { for (auto* item : FindTableItems(info)) { @@ -527,7 +475,7 @@ namespace ScriptCanvasEditor void Controller::OnUpgradeDependencySortBegin ( [[maybe_unused]] const ModifyConfiguration& config - , const WorkingAssets& assets) + , const AZStd::vector& assets) { m_handledAssetCount = 0; m_view->progressBar->setVisible(true); @@ -553,7 +501,7 @@ namespace ScriptCanvasEditor void Controller::OnUpgradeDependencySortEnd ( [[maybe_unused]] const ModifyConfiguration& config - , const WorkingAssets& assets + , const AZStd::vector& assets , [[maybe_unused]] const AZStd::vector& sortedOrder) { m_handledAssetCount = 0; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h index 9842ea3da4..ab428c0ba3 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h @@ -65,37 +65,38 @@ namespace ScriptCanvasEditor void AddLogEntries(); void EnableAllUpgradeButtons(); - QList FindTableItems(const AZ::Data::AssetInfo& assetInfo); + QList FindTableItems(const SourceHandle& assetInfo); void OnButtonPressClose(); void OnButtonPressScan(); void OnButtonPressUpgrade(); - void OnButtonPressUpgradeImplementation(const AZ::Data::AssetInfo& assetInfo); - void OnButtonPressUpgradeSingle(const AZ::Data::AssetInfo& assetInfo); + void OnButtonPressUpgradeImplementation(const SourceHandle& assetInfo); + void OnButtonPressUpgradeSingle(const SourceHandle& assetInfo); - void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped) override; + void OnGraphUpgradeComplete(SourceHandle&, bool skipped) override; void OnScanBegin(size_t assetCount) override; void OnScanComplete(const ScanResult& result) override; - void OnScanFilteredGraph(const AZ::Data::AssetInfo& info) override; - void OnScanLoadFailure(const AZ::Data::AssetInfo& info) override; - void OnScanUnFilteredGraph(const AZ::Data::AssetInfo& info) override; + void OnScanFilteredGraph(const SourceHandle& info) override; + void OnScanLoadFailure(const SourceHandle& info) override; + void OnScanUnFilteredGraph(const SourceHandle& info) override; enum class Filtered { No, Yes }; - void OnScannedGraph(const AZ::Data::AssetInfo& info, Filtered filtered); - void OnScannedGraphResult(const AZ::Data::AssetInfo& info); + void OnScannedGraph(const SourceHandle& info, Filtered filtered); + void OnScannedGraphResult(const SourceHandle& info); // for single operation UI updates, just check the assets size, or note it on the request - void OnUpgradeBegin(const ModifyConfiguration& config, const WorkingAssets& assets) override; + void OnUpgradeBegin(const ModifyConfiguration& config, const AZStd::vector& assets) override; void OnUpgradeComplete(const ModificationResults& results) override; - void OnUpgradeDependenciesGathered(const AZ::Data::AssetInfo& info, Result result) override; - void OnUpgradeDependencySortBegin(const ModifyConfiguration& config, const WorkingAssets& assets) override; + void OnUpgradeDependenciesGathered(const SourceHandle& info, Result result) override; + void OnUpgradeDependencySortBegin(const ModifyConfiguration& config, const AZStd::vector& assets) override; void OnUpgradeDependencySortEnd ( const ModifyConfiguration& config - , const WorkingAssets& assets + , const AZStd::vector& assets , const AZStd::vector& sortedOrder) override; - void OnUpgradeModificationBegin(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info) override; - void OnUpgradeModificationEnd(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info, ModificationResult result) override; - + void OnUpgradeDependencyWaitInterval(const SourceHandle& info) override; + void OnUpgradeModificationBegin(const ModifyConfiguration& config, const SourceHandle& info) override; + void OnUpgradeModificationEnd(const ModifyConfiguration& config, const SourceHandle& info, ModificationResult result) override; + void SetLoggingPreferences(); void SetSpinnerIsBusy(bool isBusy); void SetRowBusy(int index); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp index f067feeca4..57c0822b05 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp @@ -15,6 +15,7 @@ #include #include #include +#include namespace FileSaverCpp { @@ -58,6 +59,11 @@ namespace ScriptCanvasEditor , m_onComplete(onComplete) {} + const SourceHandle& FileSaver::GetSource() const + { + return m_source; + } + void FileSaver::PerformMove ( AZStd::string tmpFileName , AZStd::string target @@ -70,7 +76,7 @@ namespace ScriptCanvasEditor AZ::SystemTickBus::QueueFunction([this, tmpFileName]() { FileSaveResult result; - result.fileSaveError = "Failed to move updated file from temporary location to tmpFileName destination"; + result.fileSaveError = "Failed to move updated file from temporary location to original destination."; result.tempFileRemovalError = RemoveTempFile(tmpFileName); m_onComplete(result); }); @@ -98,7 +104,9 @@ namespace ScriptCanvasEditor auto streamer = AZ::Interface::Get(); AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); // Bump the slice asset up in the asset processor's queue. - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str()); + AzFramework::AssetSystemRequestBus::Broadcast + (&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str()); + AZ::SystemTickBus::QueueFunction([this, tmpFileName]() { FileSaveResult result; @@ -108,28 +116,29 @@ namespace ScriptCanvasEditor } else { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to tmpFileName destination failed: %s, trying again", target.c_str()); + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false + , "moving converted file to tmpFileName destination failed: %s, trying again", target.c_str()); auto streamer = AZ::Interface::Get(); AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); - streamer->SetRequestCompleteCallback(flushRequest, [this, tmpFileName, target, remainingAttempts]([[maybe_unused]] AZ::IO::FileRequestHandle request) + streamer->SetRequestCompleteCallback(flushRequest + , [this, tmpFileName, target, remainingAttempts]([[maybe_unused]] AZ::IO::FileRequestHandle request) { // Continue saving. - AZ::SystemTickBus::QueueFunction([this, tmpFileName, target, remainingAttempts]() { PerformMove(tmpFileName, target, remainingAttempts - 1); }); + AZ::SystemTickBus::QueueFunction( + [this, tmpFileName, target, remainingAttempts]() { PerformMove(tmpFileName, target, remainingAttempts - 1); }); }); streamer->QueueRequest(flushRequest); } } } - void FileSaver::OnSourceFileReleased(AZ::Data::Asset asset) + void FileSaver::OnSourceFileReleased(const SourceHandle& source) { - AZStd::string relativePath, fullPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); - bool fullPathFound = false; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); + AZStd::string fullPath = source.Path().c_str(); AZStd::string tmpFileName; // here we are saving the graph to a temp file instead of the original file and then copying the temp file to the original file. - // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. Temp files are ignored by AP. + // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. + // Temp files are ignored by AP. if (!AZ::IO::CreateTempFileName(fullPath.c_str(), tmpFileName)) { FileSaveResult result; @@ -138,23 +147,24 @@ namespace ScriptCanvasEditor return; } - bool tempSavedSucceeded = false; + AZStd::string saveError; + AZ::IO::FileIOStream fileStream(tmpFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); if (fileStream.IsOpen()) { - if (asset.GetType() == azrtti_typeid()) + auto saveOutcome = ScriptCanvasEditor::SaveToStream(source, fileStream); + if (!saveOutcome.IsSuccess()) { - ScriptCanvasEditor::ScriptCanvasAssetHandler handler; - tempSavedSucceeded = handler.SaveAssetData(asset, &fileStream); + saveError = saveOutcome.TakeError(); } fileStream.Close(); } - if (!tempSavedSucceeded) + if (!saveError.empty()) { FileSaveResult result; - result.fileSaveError = "Save asset data to temporary file failed"; + result.fileSaveError = AZStd::string::format("Save asset data to temporary file failed: %s", saveError.c_str()); m_onComplete(result); return; } @@ -164,26 +174,26 @@ namespace ScriptCanvasEditor , fullPath.c_str() , true , [this, fullPath, tmpFileName]([[maybe_unused]] bool success, const AzToolsFramework::SourceControlFileInfo& info) - { - constexpr const size_t k_maxAttemps = 10; + { + constexpr const size_t k_maxAttemps = 10; - if (!info.IsReadOnly()) - { - PerformMove(tmpFileName, fullPath, k_maxAttemps); - } - else if (m_onReadOnlyFile && m_onReadOnlyFile()) - { - AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); - PerformMove(tmpFileName, fullPath, k_maxAttemps); - } - else - { - FileSaveResult result; - result.fileSaveError = "Source file was and remained read-only"; - result.tempFileRemovalError = RemoveTempFile(tmpFileName); - m_onComplete(result); - } - }); + if (!info.IsReadOnly()) + { + PerformMove(tmpFileName, fullPath, k_maxAttemps); + } + else if (m_onReadOnlyFile && m_onReadOnlyFile()) + { + AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); + PerformMove(tmpFileName, fullPath, k_maxAttemps); + } + else + { + FileSaveResult result; + result.fileSaveError = "Source file was and remained read-only"; + result.tempFileRemovalError = RemoveTempFile(tmpFileName); + m_onComplete(result); + } + }); } AZStd::string FileSaver::RemoveTempFile(AZStd::string_view tempFile) @@ -191,7 +201,7 @@ namespace ScriptCanvasEditor AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); if (!fileIO) { - return "GraphUpgradeComplete: No FileIO instance"; + return "No FileIO instance"; } if (fileIO->Exists(tempFile.data()) && !fileIO->Remove(tempFile.data())) @@ -202,30 +212,30 @@ namespace ScriptCanvasEditor return ""; } - void FileSaver::Save(AZ::Data::Asset asset) + void FileSaver::Save(const SourceHandle& source) { - AZStd::string relativePath, fullPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); - bool fullPathFound = false; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult - (fullPathFound - , &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath - , relativePath, fullPath); + m_source = source; - if (!fullPathFound) + if (source.Path().empty()) { FileSaveResult result; - result.fileSaveError = "Full source path not found"; + result.fileSaveError = "No save location specified"; m_onComplete(result); } else { auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(fullPath); - streamer->SetRequestCompleteCallback(flushRequest, [this, asset]([[maybe_unused]] AZ::IO::FileRequestHandle request) + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(source.Path().c_str()); + streamer->SetRequestCompleteCallback(flushRequest, [this]([[maybe_unused]] AZ::IO::FileRequestHandle request) { - this->OnSourceFileReleased(asset); + AZStd::lock_guard lock(m_mutex); + if (!m_sourceFileReleased) + { + m_sourceFileReleased = true; + AZ::SystemTickBus::QueueFunction([this]() { this->OnSourceFileReleased(m_source); }); + } }); + streamer->QueueRequest(flushRequest); } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h index dd333927ed..e87ee060f7 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h @@ -29,14 +29,19 @@ namespace ScriptCanvasEditor ( AZStd::function onReadOnlyFile , AZStd::function onComplete); - void Save(AZ::Data::Asset asset); + const SourceHandle& GetSource() const; + void Save(const SourceHandle& source); private: + AZStd::mutex m_mutex; + + bool m_sourceFileReleased = false; + SourceHandle m_source; AZStd::function m_onComplete; AZStd::function m_onReadOnlyFile; - void OnSourceFileReleased(AZ::Data::Asset asset); - + void OnSourceFileReleased(const SourceHandle& source); + void PerformMove ( AZStd::string source , AZStd::string target diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp index d8d242adbb..5df1e32c8f 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp @@ -101,7 +101,7 @@ namespace ScriptCanvasEditor return; } - if (modification.modifySingleAsset.m_assetId.IsValid()) + if (!modification.modifySingleAsset.Path().empty()) { const auto& results = m_scanner->GetResult(); auto iter = AZStd::find_if @@ -109,7 +109,7 @@ namespace ScriptCanvasEditor , results.m_unfiltered.end() , [&modification](const auto& candidate) { - return candidate.info.m_assetId == modification.modifySingleAsset.m_assetId; + return candidate.AnyEquals(modification.modifySingleAsset); }); if (iter == results.m_unfiltered.end()) @@ -120,7 +120,7 @@ namespace ScriptCanvasEditor m_state = State::ModifySingle; - m_modifier = AZStd::make_unique(modification, WorkingAssets{ *iter }, [this]() { OnModificationComplete(); }); + m_modifier = AZStd::make_unique(modification, AZStd::vector{ *iter }, [this]() { OnModificationComplete(); }); } else { @@ -145,6 +145,7 @@ namespace ScriptCanvasEditor } Idle(); + RestoreSettings(); } void Model::OnScanComplete() @@ -161,6 +162,7 @@ namespace ScriptCanvasEditor return; } + CacheSettings(); m_state = State::Scanning; m_log.Activate(); m_keepEditorAlive = AZStd::make_unique(); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h index 01eb200542..9351d8c26c 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h @@ -9,53 +9,52 @@ #include #include +#include namespace ScriptCanvasEditor { namespace VersionExplorer { - struct WorkingAsset - { - AZ::Data::Asset asset; - AZ::Data::AssetInfo info; - }; - - using WorkingAssets = AZStd::vector; - struct ModifyConfiguration { - AZStd::function)> modification; + AZStd::function modification; AZStd::function onReadOnlyFile; - AZ::Data::AssetInfo modifySingleAsset; + SourceHandle modifySingleAsset; bool backupGraphBeforeModification = false; bool successfulDependencyUpgradeRequired = true; + AZ::s32 perDependencyWaitSecondsMax = 20; }; struct ModificationResult { - AZ::Data::Asset asset; - AZ::Data::AssetInfo assetInfo; + SourceHandle asset; AZStd::string errorMessage; }; struct ModificationResults { - AZStd::vector m_successes; + AZStd::vector m_successes; AZStd::vector m_failures; }; struct ScanConfiguration { - AZStd::function)> filter; + enum class Filter + { + Include, + Exclude + }; + + AZStd::function filter; bool reportFilteredGraphs = false; }; struct ScanResult { - AZStd::vector m_catalogAssets; - WorkingAssets m_unfiltered; - AZStd::vector m_filteredAssets; - AZStd::vector m_loadErrors; + AZStd::vector m_catalogAssets; + AZStd::vector m_unfiltered; + AZStd::vector m_filteredAssets; + AZStd::vector m_loadErrors; }; enum Result @@ -88,20 +87,21 @@ namespace ScriptCanvasEditor public: virtual void OnScanBegin(size_t assetCount) = 0; virtual void OnScanComplete(const ScanResult& result) = 0; - virtual void OnScanFilteredGraph(const AZ::Data::AssetInfo& info) = 0; - virtual void OnScanLoadFailure(const AZ::Data::AssetInfo& info) = 0; - virtual void OnScanUnFilteredGraph(const AZ::Data::AssetInfo& info) = 0; + virtual void OnScanFilteredGraph(const SourceHandle& info) = 0; + virtual void OnScanLoadFailure(const SourceHandle& info) = 0; + virtual void OnScanUnFilteredGraph(const SourceHandle& info) = 0; - virtual void OnUpgradeBegin(const ModifyConfiguration& config, const WorkingAssets& assets) = 0; + virtual void OnUpgradeBegin(const ModifyConfiguration& config, const AZStd::vector& assets) = 0; virtual void OnUpgradeComplete(const ModificationResults& results) = 0; - virtual void OnUpgradeDependenciesGathered(const AZ::Data::AssetInfo& info, Result result) = 0; - virtual void OnUpgradeDependencySortBegin(const ModifyConfiguration& config, const WorkingAssets& assets) = 0; + virtual void OnUpgradeDependenciesGathered(const SourceHandle& info, Result result) = 0; + virtual void OnUpgradeDependencySortBegin(const ModifyConfiguration& config, const AZStd::vector& assets) = 0; virtual void OnUpgradeDependencySortEnd ( const ModifyConfiguration& config - , const WorkingAssets& assets + , const AZStd::vector& assets , const AZStd::vector& sortedOrder) = 0; - virtual void OnUpgradeModificationBegin(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info) = 0; - virtual void OnUpgradeModificationEnd(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info, ModificationResult result) = 0; + virtual void OnUpgradeDependencyWaitInterval(const SourceHandle& info) = 0; + virtual void OnUpgradeModificationBegin(const ModifyConfiguration& config, const SourceHandle& info) = 0; + virtual void OnUpgradeModificationEnd(const ModifyConfiguration& config, const SourceHandle& info, ModificationResult result) = 0; }; using ModelNotificationsBus = AZ::EBus; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp index f3da1ba309..14b292e489 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp @@ -6,24 +6,21 @@ * */ +#include #include #include #include #include +#include #include -namespace ModifierCpp -{ - -} - namespace ScriptCanvasEditor { namespace VersionExplorer { Modifier::Modifier ( const ModifyConfiguration& modification - , WorkingAssets&& assets + , AZStd::vector&& assets , AZStd::function onComplete) : m_state(State::GatheringDependencies) , m_config(modification) @@ -33,46 +30,98 @@ namespace ScriptCanvasEditor AZ_Assert(m_config.modification, "No modification function provided"); ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeBegin, modification, m_assets); AZ::SystemTickBus::Handler::BusConnect(); + AzFramework::AssetSystemInfoBus::Handler::BusConnect(); + m_result.asset = m_assets[GetCurrentIndex()]; } - const AZ::Data::AssetInfo& Modifier::GetCurrentAsset() const + Modifier::~Modifier() { - return m_state == State::GatheringDependencies - ? m_assets[m_assetIndex].info - : m_assets[m_dependencyOrderedAssetIndicies[m_assetIndex]].info; + AzFramework::AssetSystemInfoBus::Handler::BusDisconnect(); } - AZStd::unordered_set& Modifier::GetOrCreateDependencyIndexSet() + bool Modifier::AllDependenciesCleared(const AZStd::unordered_set& dependencies) const { - auto iter = m_dependencies.find(m_assetIndex); - if (iter == m_dependencies.end()) + for (auto index : dependencies) { - iter = m_dependencies.insert_or_assign(m_assetIndex, AZStd::unordered_set()).first; + SourceHandle dependency = m_assets[index]; + CompleteDescriptionInPlace(dependency); + + if (dependency.Id().IsNull() || !m_assetsCompletedByAP.contains(dependency.Id())) + { + return false; + } } - return iter->second; + return true; } - const ModificationResults& Modifier::GetResult() const + bool Modifier::AnyDependenciesFailed(const AZStd::unordered_set& dependencies) const { - return m_results; + for (auto index : dependencies) + { + SourceHandle dependency = m_assets[index]; + CompleteDescriptionInPlace(dependency); + + if (dependency.Id().IsNull() || m_assetsFailedByAP.contains(dependency.Id())) + { + return true; + } + } + + return false; } - + + void Modifier::AssetCompilationSuccess([[maybe_unused]] const AZStd::string& assetPath) + { + AZStd::lock_guard lock(m_mutex); + m_successNotifications.insert(assetPath); + } + + void Modifier::AssetCompilationFailed(const AZStd::string& assetPath) + { + AZStd::lock_guard lock(m_mutex); + m_failureNotifications.insert(assetPath); + } + + AZStd::sys_time_t Modifier::CalculateRemainingWaitTime(const AZStd::unordered_set& dependencies) const + { + auto maxSeconds = AZStd::chrono::seconds(dependencies.size() * m_config.perDependencyWaitSecondsMax); + auto waitedSeconds = AZStd::chrono::seconds(AZStd::chrono::system_clock::now() - m_waitTimeStamp); + return (maxSeconds - waitedSeconds).count(); + } + + void Modifier::CheckDependencies() + { + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeModificationBegin, m_config, m_result.asset); + + if (auto dependencies = GetDependencies(GetCurrentIndex()); dependencies != nullptr && !dependencies->empty()) + { + VE_LOG + ( "dependencies found for %s, update will wait for the AP to finish processing them" + , m_result.asset.Path().c_str()); + + m_waitTimeStamp = AZStd::chrono::system_clock::now(); + m_waitLogTimeStamp = AZStd::chrono::system_clock::time_point{}; + m_modifyState = ModifyState::WaitingForDependencyProcessing; + } + else + { + m_modifyState = ModifyState::StartModification; + } + } + void Modifier::GatherDependencies() { AZ::SerializeContext* serializeContext{}; AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext); AZ_Assert(serializeContext, "SerializeContext is required to enumerate dependent assets in the ScriptCanvas file"); + LoadAsset(); bool anyFailures = false; - auto asset = LoadAsset(); - if (asset - && asset.GetAs() - && asset.GetAs()->GetScriptCanvasGraph() - && asset.GetAs()->GetScriptCanvasGraph()->GetGraphData()) + if (m_result.asset.Get() && m_result.asset.Mod()->GetGraphData()) { - auto graphData = asset.GetAs()->GetScriptCanvasGraph()->GetGraphData(); + auto graphData = m_result.asset.Mod()->GetGraphData(); auto dependencyGrabber = [this] ( void* instancePointer @@ -108,70 +157,101 @@ namespace ScriptCanvasEditor { anyFailures = true; VE_LOG("Modifier: ERROR - Failed to gather dependencies from graph data: %s" - , GetCurrentAsset().m_relativePath.c_str()) + , m_result.asset.Path().c_str()) } } else { anyFailures = true; VE_LOG("Modifier: ERROR - Failed to load asset %s for modification, even though it scanned properly" - , GetCurrentAsset().m_relativePath.c_str()); + , m_result.asset.Path().c_str()); } - + ModelNotificationsBus::Broadcast ( &ModelNotificationsTraits::OnUpgradeDependenciesGathered - , GetCurrentAsset() + , m_result.asset , anyFailures ? Result::Failure : Result::Success); - - // Flush asset database events to ensure no asset references are held by closures queued on Ebuses. - AZ::Data::AssetManager::Instance().DispatchEvents(); } - AZ::Data::Asset Modifier::LoadAsset() + size_t Modifier::GetCurrentIndex() const { - AZ::Data::Asset asset = AZ::Data::AssetManager::Instance().GetAsset - ( GetCurrentAsset().m_assetId - , azrtti_typeid() - , AZ::Data::AssetLoadBehavior::PreLoad); + return m_state == State::GatheringDependencies + ? m_assetIndex + : m_dependencyOrderedAssetIndicies[m_assetIndex]; + } - asset.BlockUntilLoadComplete(); + const AZStd::unordered_set* Modifier::GetDependencies(size_t index) const + { + auto iter = m_dependencies.find(index); + return iter != m_dependencies.end() ? &iter->second : nullptr; + } - if (asset.IsReady()) + AZStd::unordered_set& Modifier::GetOrCreateDependencyIndexSet() + { + auto iter = m_dependencies.find(m_assetIndex); + if (iter == m_dependencies.end()) { - return asset; + iter = m_dependencies.insert_or_assign(m_assetIndex, AZStd::unordered_set()).first; } - else + + return iter->second; + } + + const ModificationResults& Modifier::GetResult() const + { + return m_results; + } + + void Modifier::InitializeResult() + { + m_result = {}; + + if (m_assetIndex != m_assets.size()) { - return {}; + m_result.asset = m_assets[GetCurrentIndex()]; + CompleteDescriptionInPlace(m_result.asset); + m_attemptedAssets.insert(m_result.asset.Id()); + } + } + + void Modifier::LoadAsset() + { + auto& handle = m_result.asset; + if (!handle.IsGraphValid()) + { + auto outcome = LoadFromFile(handle.Path().c_str()); + if (outcome.IsSuccess()) + { + handle = outcome.TakeValue(); + } } } void Modifier::ModificationComplete(const ModificationResult& result) { - m_result = result; - - if (result.errorMessage.empty()) + if (!result.errorMessage.empty()) { - SaveModifiedGraph(result); + ReportModificationError(result.errorMessage); + } + else if (m_result.asset.Describe() != result.asset.Describe()) + { + ReportModificationError("Received modification complete notification for different result"); } else { - ReportModificationError(result.errorMessage); + SaveModifiedGraph(result); } } void Modifier::ModifyCurrentAsset() { - m_result = {}; - m_result.assetInfo = GetCurrentAsset(); + LoadAsset(); - ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeModificationBegin, m_config, GetCurrentAsset()); - - if (auto asset = LoadAsset()) + if (m_result.asset.IsGraphValid()) { ModificationNotificationsBus::Handler::BusConnect(); m_modifyState = ModifyState::InProgress; - m_config.modification(asset); + m_config.modification(m_result.asset); } else { @@ -179,44 +259,17 @@ namespace ScriptCanvasEditor } } - void Modifier::ModifyNextAsset() + void Modifier::NextAsset() { - ModelNotificationsBus::Broadcast - ( &ModelNotificationsTraits::OnUpgradeModificationEnd, m_config, GetCurrentAsset(), m_result); - ModificationNotificationsBus::Handler::BusDisconnect(); - m_modifyState = ModifyState::Idle; ++m_assetIndex; - m_result = {}; + InitializeResult(); } - void Modifier::ReportModificationError(AZStd::string_view report) + void Modifier::NextModification() { - m_result.asset = {}; - m_result.errorMessage = report; - m_results.m_failures.push_back(m_result); - ModifyNextAsset(); - } - - void Modifier::ReportModificationSuccess() - { - m_results.m_successes.push_back(m_result.assetInfo); - ModifyNextAsset(); - } - - void Modifier::ReportSaveResult() - { - AZStd::lock_guard lock(m_mutex); - m_fileSaver.reset(); - - if (m_fileSaveResult.fileSaveError.empty()) - { - ReportModificationSuccess(); - } - else - { - ReportModificationError(m_fileSaveResult.fileSaveError); - } - + ModelNotificationsBus::Broadcast( &ModelNotificationsTraits::OnUpgradeModificationEnd, m_config, m_result.asset, m_result); + ModificationNotificationsBus::Handler::BusDisconnect(); + NextAsset(); m_fileSaveResult = {}; m_modifyState = ModifyState::Idle; } @@ -226,8 +279,8 @@ namespace ScriptCanvasEditor if (!result.tempFileRemovalError.empty()) { VE_LOG - ( "Temporary file not removed for %s: %s" - , m_result.assetInfo.m_relativePath.c_str() + ("Temporary file not removed for %s: %s" + , m_result.asset.Path().c_str() , result.tempFileRemovalError.c_str()); } @@ -254,12 +307,84 @@ namespace ScriptCanvasEditor AZ::SystemTickBus::ExecuteQueuedEvents(); } + void Modifier::ProcessNotifications() + { + AZStd::lock_guard lock(m_mutex); + + for (const auto& assetPath : m_successNotifications) + { + VE_LOG("received AssetCompilationSuccess: %s", assetPath.c_str()); + SourceHandle sourceHandle(nullptr, {}, assetPath.c_str()); + CompleteDescriptionInPlace(sourceHandle); + + if (m_attemptedAssets.contains(sourceHandle.Id())) + { + m_assetsCompletedByAP.insert(sourceHandle.Id()); + } + } + + m_successNotifications.clear(); + + for (const auto& assetPath : m_failureNotifications) + { + VE_LOG("received AssetCompilationFailed: %s", assetPath.c_str()); + SourceHandle sourceHandle(nullptr, {}, assetPath.c_str()); + CompleteDescriptionInPlace(sourceHandle); + + if (m_attemptedAssets.contains(sourceHandle.Id())) + { + m_assetsFailedByAP.insert(sourceHandle.Id()); + } + } + + m_failureNotifications.clear(); + } + + void Modifier::ReleaseCurrentAsset() + { + m_result.asset = m_result.asset.Describe(); + // Flush asset database events to ensure no asset references are held by closures queued on Ebuses. + AZ::Data::AssetManager::Instance().DispatchEvents(); + } + + void Modifier::ReportModificationError(AZStd::string_view report) + { + m_result.errorMessage = report; + m_results.m_failures.push_back({ m_result.asset.Describe(), report }); + m_assetsFailedByAP.insert(m_result.asset.Id()); + NextModification(); + } + + void Modifier::ReportModificationSuccess() + { + // \note DO NOT put asset into the m_assetsCompletedByAP here. That can only be done when the message is received by the AP + m_results.m_successes.push_back({ m_result.asset.Describe(), {} }); + AzFramework::AssetSystemRequestBus::Broadcast( + &AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetByUuid, m_result.asset.Id()); + NextModification(); + } + + void Modifier::ReportSaveResult() + { + AZStd::lock_guard lock(m_mutex); + m_fileSaver.reset(); + + if (m_fileSaveResult.fileSaveError.empty()) + { + ReportModificationSuccess(); + } + else + { + ReportModificationError(m_fileSaveResult.fileSaveError); + } + } + void Modifier::SaveModifiedGraph(const ModificationResult& result) { m_modifyState = ModifyState::Saving; m_fileSaver = AZStd::make_unique ( m_config.onReadOnlyFile - , [this](const FileSaveResult& result) { OnFileSaveComplete(result); }); + , [this](const FileSaveResult& fileSaveResult) { OnFileSaveComplete(fileSaveResult); }); m_fileSaver->Save(result.asset); } @@ -287,7 +412,7 @@ namespace ScriptCanvasEditor for (size_t index = 0; index != m_assets.size(); ++index) { - m_assetInfoIndexById.insert({ m_assets[index].info.m_assetId.m_guid, index }); + m_assetInfoIndexById.insert({ m_assets[index].Id(), index }); } } else @@ -299,7 +424,7 @@ namespace ScriptCanvasEditor m_dependencyOrderedAssetIndicies.push_back(index); } - // go straight into ModifyinGraphs + // go straight into ModifyingGraphs m_assetIndex = m_assets.size(); } } @@ -318,48 +443,87 @@ namespace ScriptCanvasEditor m_assetIndex = 0; m_state = State::ModifyingGraphs; + InitializeResult(); } else { GatherDependencies(); - ++m_assetIndex; + NextAsset(); } } void Modifier::TickUpdateGraph() { - if (m_assetIndex == m_assets.size()) - { - VE_LOG("Modifier: Complete."); - AZ::SystemTickBus::Handler::BusDisconnect(); + AZStd::lock_guard lock(m_mutex); - if (m_onComplete) + switch (m_modifyState) + { + case ScriptCanvasEditor::VersionExplorer::Modifier::ModifyState::Idle: + if (m_assetIndex == m_assets.size()) { - m_onComplete(); + VE_LOG("Modifier: Complete."); + AZ::SystemTickBus::Handler::BusDisconnect(); + + if (m_onComplete) + { + m_onComplete(); + } } + else + { + CheckDependencies(); + } + break; + case ScriptCanvasEditor::VersionExplorer::Modifier::ModifyState::WaitingForDependencyProcessing: + WaitForDependencies(); + break; + case ScriptCanvasEditor::VersionExplorer::Modifier::ModifyState::StartModification: + ModifyCurrentAsset(); + break; + case ScriptCanvasEditor::VersionExplorer::Modifier::ModifyState::ReportResult: + ReportSaveResult(); + break; + default: + break; } - else - { - AZStd::lock_guard lock(m_mutex); + } - switch (m_modifyState) - { - case ScriptCanvasEditor::VersionExplorer::Modifier::ModifyState::Idle: - ModifyCurrentAsset(); - break; - case ScriptCanvasEditor::VersionExplorer::Modifier::ModifyState::ReportResult: - ReportSaveResult(); - break; - default: - break; - } + void Modifier::WaitForDependencies() + { + const AZ::s32 LogPeriodSeconds = 5; + + ProcessNotifications(); + + auto dependencies = GetDependencies(GetCurrentIndex()); + if (dependencies == nullptr || dependencies->empty() || AllDependenciesCleared(*dependencies)) + { + m_modifyState = ModifyState::StartModification; + } + else if (AnyDependenciesFailed(*dependencies)) + { + ReportModificationError("A required dependency failed to update, graph cannot update."); + } + else if (AZStd::chrono::seconds(CalculateRemainingWaitTime(*dependencies)).count() < 0) + { + ReportModificationError("Dependency update time has taken too long, aborting modification."); + } + else if (AZStd::chrono::seconds(AZStd::chrono::system_clock::now() - m_waitLogTimeStamp).count() > LogPeriodSeconds) + { + m_waitLogTimeStamp = AZStd::chrono::system_clock::now(); + + AZ_TracePrintf + ( ScriptCanvas::k_VersionExplorerWindow.data() + , "Waiting for dependencies for %d more seconds: %s" + , AZStd::chrono::seconds(CalculateRemainingWaitTime(*dependencies)).count() + , m_result.asset.Path().c_str()); + + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeDependencyWaitInterval, m_result.asset); } } const AZStd::unordered_set* Modifier::Sorter::GetDependencies(size_t index) const { - auto iter = modifier->m_dependencies.find(index); - return iter != modifier->m_dependencies.end() ? &iter->second : nullptr; + return modifier->GetDependencies(index); } void Modifier::Sorter::Sort() @@ -380,10 +544,10 @@ namespace ScriptCanvasEditor if (markedTemporary.contains(index)) { AZ_Error - (ScriptCanvas::k_VersionExplorerWindow.data() + ( ScriptCanvas::k_VersionExplorerWindow.data() , false , "Modifier: Dependency sort has failed during, circular dependency detected for Asset: %s" - , modifier->GetCurrentAsset().m_relativePath.c_str()); + , modifier->m_result.asset.Path().c_str()); return; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h index 981a1eb746..d5147cab61 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include #include @@ -17,18 +18,21 @@ namespace ScriptCanvasEditor { namespace VersionExplorer { - class Modifier - : private AZ::SystemTickBus::Handler - , private ModificationNotificationsBus::Handler + class Modifier final + : public AZ::SystemTickBus::Handler + , public ModificationNotificationsBus::Handler + , public AzFramework::AssetSystemInfoBus::Handler { public: AZ_CLASS_ALLOCATOR(Modifier, AZ::SystemAllocator, 0); Modifier ( const ModifyConfiguration& modification - , WorkingAssets&& assets + , AZStd::vector&& assets , AZStd::function onComplete); + ~Modifier(); + const ModificationResults& GetResult() const; ModificationResults&& TakeResult(); @@ -56,6 +60,8 @@ namespace ScriptCanvasEditor enum class ModifyState { Idle, + WaitingForDependencyProcessing, + StartModification, InProgress, Saving, ReportResult @@ -67,37 +73,58 @@ namespace ScriptCanvasEditor State m_state = State::GatheringDependencies; ModifyState m_modifyState = ModifyState::Idle; size_t m_assetIndex = 0; + AZStd::function m_onComplete; // asset infos in scanned order - WorkingAssets m_assets; + AZStd::vector m_assets; // dependency sorted order indices into the asset vector AZStd::vector m_dependencyOrderedAssetIndicies; // dependency indices by asset info index (only exist if graphs have them) AZStd::unordered_map> m_dependencies; AZStd::unordered_map m_assetInfoIndexById; - AZStd::vector m_failures; ModifyConfiguration m_config; ModificationResult m_result; ModificationResults m_results; AZStd::unique_ptr m_fileSaver; FileSaveResult m_fileSaveResult; + // m_attemptedAssets is assets attempted to be processed by modification, as opposed to + // those processed by the AP as a result of one of their dependencies being processed. + AZStd::unordered_set m_attemptedAssets; + AZStd::unordered_set m_assetsCompletedByAP; + AZStd::unordered_set m_assetsFailedByAP; + AZStd::chrono::system_clock::time_point m_waitLogTimeStamp; + AZStd::chrono::system_clock::time_point m_waitTimeStamp; + AZStd::unordered_set m_successNotifications; + AZStd::unordered_set m_failureNotifications; + bool AllDependenciesCleared(const AZStd::unordered_set& dependencies) const; + bool AnyDependenciesFailed(const AZStd::unordered_set& dependencies) const; + void AssetCompilationSuccess(const AZStd::string& assetPath) override; + void AssetCompilationFailed(const AZStd::string& assetPath) override; + AZStd::sys_time_t CalculateRemainingWaitTime(const AZStd::unordered_set& dependencies) const; + void CheckDependencies(); void GatherDependencies(); - const AZ::Data::AssetInfo& GetCurrentAsset() const; + size_t GetCurrentIndex() const; + const AZStd::unordered_set* GetDependencies(size_t index) const; AZStd::unordered_set& GetOrCreateDependencyIndexSet(); - AZ::Data::Asset LoadAsset(); - void ModifyCurrentAsset(); - void ModifyNextAsset(); + void InitializeResult(); + void LoadAsset(); void ModificationComplete(const ModificationResult& result) override; + void ModifyCurrentAsset(); + void NextAsset(); + void NextModification(); + void OnFileSaveComplete(const FileSaveResult& result); + void OnSystemTick() override; + void ProcessNotifications(); + void ReleaseCurrentAsset(); void ReportModificationError(AZStd::string_view report); void ReportModificationSuccess(); void ReportSaveResult(); void SaveModifiedGraph(const ModificationResult& result); void SortGraphsByDependencies(); - void OnFileSaveComplete(const FileSaveResult& result); - void OnSystemTick() override; void TickGatherDependencies(); void TickUpdateGraph(); + void WaitForDependencies(); }; } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp index bc69f6e634..816ded8a7b 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp @@ -6,9 +6,49 @@ * */ +#include +#include +#include +#include +#include #include #include -#include +#include + +namespace ScannerCpp +{ + void TraverseTree + ( QModelIndex index + , AzToolsFramework::AssetBrowser::AssetBrowserFilterModel& model + , ScriptCanvasEditor::VersionExplorer::ScanResult& result) + { + QModelIndex sourceIndex = model.mapToSource(index); + AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry = + reinterpret_cast(sourceIndex.internalPointer()); + + if (entry + && entry->GetEntryType() == AzToolsFramework::AssetBrowser::AssetBrowserEntry::AssetEntryType::Source + && azrtti_istypeof(entry) + && entry->GetFullPath().ends_with(".scriptcanvas")) + { + auto sourceEntry = azrtti_cast(entry); + + AZStd::string fullPath = sourceEntry->GetFullPath(); + AzFramework::StringFunc::Path::Normalize(fullPath); + + result.m_catalogAssets.push_back( + ScriptCanvasEditor::SourceHandle(nullptr, sourceEntry->GetSourceUuid(), fullPath)); + } + + const int rowCount = model.rowCount(index); + + for (int i = 0; i < rowCount; ++i) + { + TraverseTree(model.index(i, 0, index), model, result); + } + } +} + namespace ScriptCanvasEditor { @@ -18,60 +58,54 @@ namespace ScriptCanvasEditor : m_config(config) , m_onComplete(onComplete) { - AZ::Data::AssetCatalogRequestBus::Broadcast - ( &AZ::Data::AssetCatalogRequestBus::Events::EnumerateAssets - , nullptr - , [this](const AZ::Data::AssetId, const AZ::Data::AssetInfo& assetInfo) - { - if (assetInfo.m_assetType == azrtti_typeid()) - { - m_result.m_catalogAssets.push_back(assetInfo); - } - } - , nullptr); + AzToolsFramework::AssetBrowser::AssetBrowserModel* assetBrowserModel = nullptr; + AzToolsFramework::AssetBrowser::AssetBrowserComponentRequestBus::BroadcastResult + ( assetBrowserModel, &AzToolsFramework::AssetBrowser::AssetBrowserComponentRequests::GetAssetBrowserModel); + + if (assetBrowserModel) + { + auto stringFilter = new AzToolsFramework::AssetBrowser::StringFilter(); + stringFilter->SetName("ScriptCanvas"); + stringFilter->SetFilterString(".scriptcanvas"); + stringFilter->SetFilterPropagation(AzToolsFramework::AssetBrowser::AssetBrowserEntryFilter::PropagateDirection::Down); + + AzToolsFramework::AssetBrowser::AssetBrowserFilterModel assetFilterModel; + assetFilterModel.SetFilter(AzToolsFramework::AssetBrowser::FilterConstType(stringFilter)); + assetFilterModel.setSourceModel(assetBrowserModel); + + ScannerCpp::TraverseTree(QModelIndex(), assetFilterModel, m_result); + } - ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanBegin, m_result.m_catalogAssets.size()); AZ::SystemTickBus::Handler::BusConnect(); } - void Scanner::FilterAsset(AZ::Data::Asset asset) + void Scanner::FilterAsset(SourceHandle asset) { - if (m_config.filter && m_config.filter(asset)) + if (m_config.filter && m_config.filter(asset) == ScanConfiguration::Filter::Exclude) { - VE_LOG("Scanner: Excluded: %s ", GetCurrentAsset().m_relativePath.c_str()); - m_result.m_filteredAssets.push_back(GetCurrentAsset()); - ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanFilteredGraph, GetCurrentAsset()); + VE_LOG("Scanner: Excluded: %s ", ModCurrentAsset().Path().c_str()); + m_result.m_filteredAssets.push_back(ModCurrentAsset().Describe()); + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanFilteredGraph, ModCurrentAsset()); } else { - VE_LOG("Scanner: Included: %s ", GetCurrentAsset().m_relativePath.c_str()); - m_result.m_unfiltered.push_back({ asset, GetCurrentAsset() }); - ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanUnFilteredGraph, GetCurrentAsset()); + VE_LOG("Scanner: Included: %s ", ModCurrentAsset().Path().c_str()); + m_result.m_unfiltered.push_back(ModCurrentAsset().Describe()); + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanUnFilteredGraph, ModCurrentAsset()); } } - const AZ::Data::AssetInfo& Scanner::GetCurrentAsset() const - { - return m_result.m_catalogAssets[m_catalogAssetIndex]; - } - const ScanResult& Scanner::GetResult() const { return m_result; } - AZ::Data::Asset Scanner::LoadAsset() + SourceHandle Scanner::LoadAsset() { - AZ::Data::Asset asset = AZ::Data::AssetManager::Instance().GetAsset - ( GetCurrentAsset().m_assetId - , azrtti_typeid() - , AZ::Data::AssetLoadBehavior::PreLoad); - - asset.BlockUntilLoadComplete(); - - if (asset.IsReady()) + auto fileOutcome = LoadFromFile(ModCurrentAsset().Path().c_str()); + if (fileOutcome.IsSuccess()) { - return asset; + return fileOutcome.GetValue(); } else { @@ -79,6 +113,11 @@ namespace ScriptCanvasEditor } } + SourceHandle& Scanner::ModCurrentAsset() + { + return m_result.m_catalogAssets[m_catalogAssetIndex]; + } + void Scanner::OnSystemTick() { if (m_catalogAssetIndex == m_result.m_catalogAssets.size()) @@ -93,19 +132,19 @@ namespace ScriptCanvasEditor } else { - if (auto asset = LoadAsset()) + if (auto asset = LoadAsset(); asset.IsGraphValid()) { - VE_LOG("Scanner: Loaded: %s ", GetCurrentAsset().m_relativePath.c_str()); + VE_LOG("Scanner: Loaded: %s ", ModCurrentAsset().Path().c_str()); FilterAsset(asset); } else { - VE_LOG("Scanner: Failed to load: %s ", GetCurrentAsset().m_relativePath.c_str()); - m_result.m_loadErrors.push_back(GetCurrentAsset()); - ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanLoadFailure, GetCurrentAsset()); + VE_LOG("Scanner: Failed to load: %s ", ModCurrentAsset().Path().c_str()); + m_result.m_loadErrors.push_back(ModCurrentAsset().Describe()); + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanLoadFailure, ModCurrentAsset()); } - VE_LOG("Scanner: scan of %s complete", GetCurrentAsset().m_relativePath.c_str()); + VE_LOG("Scanner: scan of %s complete", ModCurrentAsset().Path().c_str()); ++m_catalogAssetIndex; } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h index fb030845c7..8e086a10b0 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h @@ -33,9 +33,9 @@ namespace ScriptCanvasEditor ScanConfiguration m_config; ScanResult m_result; - void FilterAsset(AZ::Data::Asset); - const AZ::Data::AssetInfo& GetCurrentAsset() const; - AZ::Data::Asset LoadAsset(); + void FilterAsset(SourceHandle); + SourceHandle LoadAsset(); + SourceHandle& ModCurrentAsset(); void OnSystemTick() override; }; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp index 14bc1c4dc8..c557a83f0c 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp @@ -55,26 +55,25 @@ namespace ScriptCanvasEditor for (auto& failedUpdate : result->m_failures) { - auto& assetInfo = failedUpdate.assetInfo; - auto assetId = assetInfo.m_assetId; - + auto asset = failedUpdate.asset; + m_ui->tableWidget->insertRow(rows); connect(m_ui->closeButton, &QPushButton::pressed, this, &QDialog::accept); - connect(m_ui->tableWidget, &QTableWidget::itemDoubleClicked, this, [this, rows, assetId](QTableWidgetItem* item) + connect(m_ui->tableWidget, &QTableWidget::itemDoubleClicked, this, [this, rows, asset](QTableWidgetItem* item) { if (item && item->data(Qt::UserRole).toInt() == rows) { - OpenGraph(assetId); + OpenGraph(asset); } } ); - auto openGraph = [this, assetId] { - OpenGraph(assetId); + auto openGraph = [this, asset] { + OpenGraph(asset); }; - QTableWidgetItem* rowName = new QTableWidgetItem(tr(assetInfo.m_relativePath.c_str())); + QTableWidgetItem* rowName = new QTableWidgetItem(tr(asset.Path().c_str())); rowName->setData(Qt::UserRole, rows); m_ui->tableWidget->setItem(rows, 0, rowName); @@ -91,15 +90,15 @@ namespace ScriptCanvasEditor } } - void UpgradeHelper::OpenGraph(AZ::Data::AssetId assetId) + void UpgradeHelper::OpenGraph(const SourceHandle& asset) { // Open the graph in SC editor AzToolsFramework::OpenViewPane(/*LyViewPane::ScriptCanvas*/"Script Canvas"); AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); - if (assetId.IsValid()) + if (!asset.Path().empty()) { - GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, assetId, -1); + GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, asset, Tracker::ScriptCanvasFileState::UNMODIFIED, -1); } if (!openOutcome) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.h index 36949c1828..4c0c073d70 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.h @@ -35,6 +35,8 @@ namespace Ui namespace ScriptCanvasEditor { + // class SourceHandle; + //! A tool that collects and upgrades all Script Canvas graphs in the asset catalog class UpgradeHelper : public AzQtComponents::StyledDialog @@ -51,6 +53,6 @@ namespace ScriptCanvasEditor AZStd::unique_ptr m_ui; - void OpenGraph(AZ::Data::AssetId assetId); + void OpenGraph(const SourceHandle& assetId); }; } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/ScriptCanvasAssetBase.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/ScriptCanvasAssetBase.h index 265c35d310..1dc0b38e01 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/ScriptCanvasAssetBase.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/ScriptCanvasAssetBase.h @@ -8,16 +8,17 @@ #pragma once +#include #include #include #include - #include namespace ScriptCanvas { class ScriptCanvasAssetBase : public AZ::Data::AssetData + , public AZStd::enable_shared_from_this , ScriptCanvas::ScriptCanvasAssetBusRequestBus::Handler { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp index 9b2d0e4982..1ac7a33821 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp @@ -6,15 +6,18 @@ * */ + #include #include #include #include #include #include +#include -#include "Core.h" #include "Attributes.h" +#include "Core.h" +#include namespace ScriptCanvas { @@ -182,5 +185,156 @@ namespace ScriptCanvas serializeContext->RegisterType(typeId, AZStd::move(classData), EventPlaceholderAnyCreator); } - +} + +namespace ScriptCanvasEditor +{ + SourceHandle::SourceHandle() + : m_id(AZ::Uuid::CreateNull()) + {} + + SourceHandle::SourceHandle(const SourceHandle& data, const AZ::Uuid& id, const AZ::IO::Path& path) + : m_data(data.m_data) + , m_id(id) + , m_path(path) + { + m_path.MakePreferred(); + m_id = id; + } + + SourceHandle::SourceHandle(ScriptCanvas::DataPtr graph, const AZ::Uuid& id, const AZ::IO::Path& path) + : m_data(graph) + , m_id(id) + , m_path(path) + { + m_path.MakePreferred(); + m_id = id; + } + + SourceHandle::SourceHandle(const SourceHandle& data, const AZ::IO::Path& path) + : m_data(data.m_data) + , m_id(AZ::Uuid::CreateNull()) + , m_path(path) + { + m_path.MakePreferred(); + } + + SourceHandle::SourceHandle(ScriptCanvas::DataPtr graph, const AZ::IO::Path& path) + : m_data(graph) + , m_id(AZ::Uuid::CreateNull()) + , m_path(path) + { + m_path.MakePreferred(); + } + + bool SourceHandle::AnyEquals(const SourceHandle& other) const + { + return m_data && m_data == other.m_data + || !m_id.IsNull() && m_id == other.m_id + || !m_path.empty() && m_path == other.m_path; + } + + void SourceHandle::Clear() + { + m_data = nullptr; + m_id = AZ::Uuid::CreateNull(); + m_path.clear(); + } + + // return a SourceHandle with only the Id and Path, but without a pointer to the data + SourceHandle SourceHandle::Describe() const + { + return SourceHandle(nullptr, m_id, m_path); + } + + GraphPtrConst SourceHandle::Get() const + { + return m_data ? m_data->GetEditorGraph() : nullptr; + } + + const AZ::Uuid& SourceHandle::Id() const + { + return m_id; + } + + bool SourceHandle::IsDescriptionValid() const + { + return !m_id.IsNull() && !m_path.empty(); + } + + bool SourceHandle::IsGraphValid() const + { + return m_data != nullptr; + } + + GraphPtr SourceHandle::Mod() const + { + return m_data ? m_data->ModEditorGraph() : nullptr; + } + + bool SourceHandle::operator==(const SourceHandle& other) const + { + return m_data.get() == other.m_data.get() + && m_id == other.m_id + && m_path == other.m_path; + } + + bool SourceHandle::operator!=(const SourceHandle& other) const + { + return !(*this == other); + } + + const AZ::IO::Path& SourceHandle::Path() const + { + return m_path; + } + + bool SourceHandle::PathEquals(const SourceHandle& other) const + { + return m_path == other.m_path; + } + + void SourceHandle::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(0) + ->Field("id", &SourceHandle::m_id) + ->Field("path", &SourceHandle::m_path) + ; + } + } + + AZStd::string SourceHandle::ToString() const + { + return AZStd::string::format + ( "%s, %s, %s" + , IsGraphValid() ? "O" : "X" + , m_path.empty() ? m_path.c_str() : "" + , m_id.IsNull() ? "" : m_id.ToString().c_str()); + } +} + +namespace ScriptCanvas +{ + const Graph* ScriptCanvasData::GetGraph() const + { + return AZ::EntityUtils::FindFirstDerivedComponent(m_scriptCanvasEntity.get()); + } + + const ScriptCanvasEditor::Graph* ScriptCanvasData::GetEditorGraph() const + { + return reinterpret_cast(GetGraph()); + } + + Graph* ScriptCanvasData::ModGraph() + { + return AZ::EntityUtils::FindFirstDerivedComponent(m_scriptCanvasEntity.get()); + } + + ScriptCanvasEditor::Graph* ScriptCanvasData::ModEditorGraph() + { + return reinterpret_cast(ModGraph()); + } } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h index 0e64c19dcb..215041e1fd 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h @@ -9,18 +9,19 @@ #pragma once #include +#include +#include +#include #include +#include #include #include -#include #include +#include #include #include #include #include -#include -#include - #include #include @@ -61,6 +62,10 @@ namespace ScriptCanvas class Node; class Edge; + class Graph; + + using GraphPtr = Graph*; + using GraphPtrConst = const Graph*; using ID = AZ::EntityId; @@ -297,6 +302,105 @@ namespace ScriptCanvas void ReflectEventTypeOnDemand(const AZ::TypeId& typeId, AZStd::string_view name, AZ::IRttiHelper* rttiHelper = nullptr); } +namespace ScriptCanvas +{ + class ScriptCanvasData; + + using DataPtr = AZStd::intrusive_ptr; + using DataPtrConst = AZStd::intrusive_ptr; +} + +namespace ScriptCanvasEditor +{ + class Graph; + + using GraphPtr = Graph*; + using GraphPtrConst = const Graph*; + + class SourceHandle + { + public: + AZ_TYPE_INFO(SourceHandle, "{65855A98-AE2F-427F-BFC8-69D45265E312}"); + AZ_CLASS_ALLOCATOR(SourceHandle, AZ::SystemAllocator, 0); + + static void Reflect(AZ::ReflectContext* context); + + SourceHandle(); + + SourceHandle(const SourceHandle& data, const AZ::Uuid& id, const AZ::IO::Path& path); + + SourceHandle(ScriptCanvas::DataPtr graph, const AZ::Uuid& id, const AZ::IO::Path& path); + + SourceHandle(const SourceHandle& data, const AZ::IO::Path& path); + + SourceHandle(ScriptCanvas::DataPtr graph, const AZ::IO::Path& path); + + bool AnyEquals(const SourceHandle& other) const; + + void Clear(); + + // return a SourceHandle with only the Id and Path, but without a pointer to the data + SourceHandle Describe() const; + + GraphPtrConst Get() const; + + const AZ::Uuid& Id() const; + + bool IsDescriptionValid() const; + + bool IsGraphValid() const; + + GraphPtr Mod() const; + + bool operator==(const SourceHandle& other) const; + + bool operator!=(const SourceHandle& other) const; + + const AZ::IO::Path& Path() const; + + bool PathEquals(const SourceHandle& other) const; + + AZStd::string ToString() const; + + private: + ScriptCanvas::DataPtr m_data; + AZ::Uuid m_id = AZ::Uuid::CreateNull(); + AZ::IO::Path m_path; + }; +} + +namespace ScriptCanvas +{ + class ScriptCanvasData + : public AZStd::intrusive_refcount + { + public: + + AZ_RTTI(ScriptCanvasData, "{1072E894-0C67-4091-8B64-F7DB324AD13C}"); + AZ_CLASS_ALLOCATOR(ScriptCanvasData, AZ::SystemAllocator, 0); + ScriptCanvasData() = default; + virtual ~ScriptCanvasData() = default; + ScriptCanvasData(ScriptCanvasData&& other); + ScriptCanvasData& operator=(ScriptCanvasData&& other); + + static void Reflect(AZ::ReflectContext* reflectContext); + + AZ::Entity* GetScriptCanvasEntity() const { return m_scriptCanvasEntity.get(); } + + const Graph* GetGraph() const; + + const ScriptCanvasEditor::Graph* GetEditorGraph() const; + + Graph* ModGraph(); + + ScriptCanvasEditor::Graph* ModEditorGraph(); + + AZStd::unique_ptr m_scriptCanvasEntity; + private: + ScriptCanvasData(const ScriptCanvasData&) = delete; + }; +} + namespace AZStd { template<> @@ -304,11 +408,28 @@ namespace AZStd { using argument_type = ScriptCanvas::SlotId; using result_type = AZStd::size_t; - AZ_FORCE_INLINE size_t operator()(const argument_type& ref) const + + inline size_t operator()(const argument_type& ref) const { return AZStd::hash()(ref.m_id); } }; + + template<> + struct hash + { + using argument_type = ScriptCanvasEditor::SourceHandle; + using result_type = AZStd::size_t; + + inline size_t operator()(const argument_type& handle) const + { + size_t h = 0; + hash_combine(h, handle.Id()); + hash_combine(h, handle.Path()); + hash_combine(h, handle.Get()); + return h; + } + }; } #define SCRIPT_CANVAS_INFINITE_LOOP_DETECTION_COUNT (2000000) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp index 9d848ff998..b58e4d1536 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp @@ -52,6 +52,7 @@ namespace GraphCpp VariablePanelSymantics, AddVersionData, RemoveFunctionGraphMarker, + FixupVersionDataTypeId, // label your version above Current }; @@ -71,11 +72,31 @@ namespace ScriptCanvas componentElementNode.AddElementWithData(context, "m_assetType", azrtti_typeid()); } - if (componentElementNode.GetVersion() < GraphCpp::GraphVersion::RemoveFunctionGraphMarker) + if (auto subElement = componentElementNode.FindElement(AZ_CRC_CE("isFunctionGraph")); subElement > 0) { - componentElementNode.RemoveElementByName(AZ_CRC_CE("isFunctionGraph")); + componentElementNode.RemoveElement(subElement); } + if (auto subElement = componentElementNode.FindSubElement(AZ_CRC_CE("versionData"))) + { + if (subElement->GetId() == azrtti_typeid()) + { + componentElementNode.RemoveElementByName(AZ_CRC_CE("versionData")); + } + } + + if (componentElementNode.GetVersion() < GraphCpp::GraphVersion::FixupVersionDataTypeId) + { + if (auto subElement = componentElementNode.FindSubElement(AZ_CRC_CE("versionData"))) + { + if (subElement->GetId() == azrtti_typeid()) + { + componentElementNode.RemoveElementByName(AZ_CRC_CE("versionData")); + componentElementNode.AddElementWithData(context, "versionData", VersionData()); + } + } + } + return true; } @@ -1190,11 +1211,6 @@ namespace ScriptCanvas m_isObserved = isObserved; } - AZ::Data::AssetType Graph::GetAssetType() const - { - return m_assetType; - } - void Graph::VersioningRemoveSlot(ScriptCanvas::Node& scriptCanvasNode, const SlotId& slotId) { bool deletedSlot = true; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.h index 46e8a103bb..76fc3a6c7b 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.h @@ -14,14 +14,12 @@ #include #include #include - #include #include #include #include #include #include - #include namespace ScriptCanvas @@ -189,8 +187,6 @@ namespace ScriptCanvas bool IsGraphObserved() const override; void SetIsGraphObserved(bool isObserved) override; - - AZ::Data::AssetType GetAssetType() const override; //// const AZStd::unordered_map& GetNodeMapping() const { return m_nodeMapping; } @@ -200,7 +196,7 @@ namespace ScriptCanvas GraphData m_graphData; AZ::Data::AssetType m_assetType; - + private: ScriptCanvasId m_scriptCanvasId; ExecutionMode m_executionMode = ExecutionMode::Interpreted; @@ -209,7 +205,7 @@ namespace ScriptCanvas GraphVariableManagerRequests* m_variableRequests = nullptr; // Keeps a mapping of the Node EntityId -> NodeComponent. - // Saves looking up the NodeComponent everytime we need the Node. + // Saves looking up the NodeComponent every time we need the Node. AZStd::unordered_map m_nodeMapping; bool m_isObserved; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/GraphBus.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/GraphBus.h index 6b7133d47e..53d1a95964 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/GraphBus.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/GraphBus.h @@ -147,9 +147,6 @@ namespace ScriptCanvas //! returns a pair of with the supplied id //! The variable datum pointer is non-null if the variable has been found virtual GraphVariable* FindVariableById(const VariableId& variableId) = 0; - - virtual AZ::Data::AssetType GetAssetType() const = 0; - }; using GraphRequestBus = AZ::EBus; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp index 093f87e1f7..7bb37a87dc 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp @@ -80,6 +80,7 @@ namespace ScriptCanvas ->Attribute(AZ::ScriptCanvasAttributes::VariableCreationForbidden, AZ::AttributeIsValid::IfPresent) ->Attribute(AZ::Script::Attributes::UseClassIndexAllowNil, AZ::AttributeIsValid::IfPresent) ->Constructor() + ->Attribute(AZ::Script::Attributes::DefaultConstructorOverrideIndex, 0) ->Method("Deactivate", &Nodeable::Deactivate) ->Method("InitializeExecutionState", &Nodeable::InitializeExecutionState) ->Method("InitializeExecutionOuts", &Nodeable::InitializeExecutionOuts) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp index bbd16dfb96..561708dea1 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp @@ -68,7 +68,7 @@ namespace ExecutionInterpretedAPICpp { if (lua_isstring(lua, -1)) { - AZ::ScriptContext::FromNativeContext(lua)->Error(AZ::ScriptContext::ErrorType::Error, true, "%s", lua_tostring(lua, -1)); + AZ::ScriptContext::FromNativeContext(lua)->Error(AZ::ScriptContext::ErrorType::Error, true, lua_tostring(lua, -1)); } else { @@ -401,7 +401,7 @@ namespace ScriptCanvas // \note: the the object is being constructed, and is assumed to never leave or re-enter Lua again AZ_Assert(lua_isuserdata(lua, -2) && !lua_islightuserdata(lua, -2), "Error in compiled lua file, 1st argument to OverrideNodeableMetatable is not userdata (Nodeable)"); AZ_Assert(lua_istable(lua, -1), "Error in compiled lua file, 2nd argument to OverrideNodeableMetatable is not a Lua table"); - + [[maybe_unused]] auto userData = reinterpret_cast(lua_touserdata(lua, -2)); AZ_Assert(userData && userData->magicData == AZ_CRC_CE("AZLuaUserData"), "this isn't user data"); // Lua: LuaUserData::nodeable, class_mt @@ -503,20 +503,21 @@ namespace ScriptCanvas void InitializeInterpretedStatics(RuntimeData& runtimeData) { - if (!runtimeData.m_areStaticsInitialized) + AZ_Error("ScriptCanvas", !runtimeData.m_areStaticsInitialized, "ScriptCanvas runtime data already initalized"); { runtimeData.m_areStaticsInitialized = true; for (auto& dependency : runtimeData.m_requiredAssets) { - InitializeInterpretedStatics(dependency.Get()->GetData()); + if (!dependency.Get()->GetData().m_areStaticsInitialized) + { + InitializeInterpretedStatics(dependency.Get()->GetData()); + } } #if defined(AZ_PROFILE_BUILD) || defined(AZ_DEBUG_BUILD) Execution::InitializeFromLuaStackFunctions(const_cast(runtimeData.m_debugMap)); #endif - AZ_WarningOnce("ScriptCanvas", !runtimeData.m_areStaticsInitialized, "ScriptCanvas runtime data already initalized"); - if (runtimeData.RequiresStaticInitialization()) { AZ::ScriptLoadResult result{}; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpreted.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpreted.cpp index 0f090574b5..3b963317ec 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpreted.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpreted.cpp @@ -49,7 +49,10 @@ namespace ScriptCanvas , config.asset.GetId().ToString().data()); #endif - Execution::InitializeInterpretedStatics(runtimeAsset->GetData()); + if (!runtimeAsset->GetData().m_areStaticsInitialized) + { + Execution::InitializeInterpretedStatics(runtimeAsset->GetData()); + } } void ExecutionStateInterpreted::ClearLuaRegistryIndex() @@ -143,6 +146,8 @@ namespace ScriptCanvas AZ_Assert(m_luaRegistryIndex == LUA_NOREF, "ExecutionStateInterpreted already in the Lua registry and risks double deletion"); // Lua: instance m_luaRegistryIndex = luaL_ref(m_luaState, LUA_REGISTRYINDEX); + AZ_Assert(m_luaRegistryIndex != LUA_REFNIL, "ExecutionStateInterpreted was nil when trying to gain a reference"); + AZ_Assert(m_luaRegistryIndex != LUA_NOREF, "ExecutionStateInterpreted failed to gain a reference"); } void ExecutionStateInterpreted::Reflect(AZ::ReflectContext* reflectContext) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpretedPerActivation.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpretedPerActivation.cpp index 44b1364682..425af171c5 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpretedPerActivation.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpretedPerActivation.cpp @@ -117,7 +117,7 @@ namespace ScriptCanvas lua_pushvalue(lua, -2); // Lua: instance, graph_VM.k_OnGraphStartFunctionName, instance const int result = Execution::InterpretedSafeCall(lua, 1, 0); - // Lua: instance ? + // Lua: instance, ? if (result == LUA_OK) { // Lua: instance diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp index 7d76dbc27d..829a1098dc 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp @@ -2384,9 +2384,8 @@ namespace ScriptCanvas AZ_TracePrintf("ScriptCanvas", "%s", pretty.data()); AZ_TracePrintf("ScriptCanvas", "SubgraphInterface:"); AZ_TracePrintf("ScriptCanvas", ToString(m_subgraphInterface).data()); + AZ_TracePrintf("Script Canvas", "Parse Duration: %8.4f ms\n", m_parseDuration / 1000.0); } - - AZ_TracePrintf("Script Canvas", "Parse Duration: %8.4f ms\n", m_parseDuration / 1000.0); } } } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingMetaData.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingMetaData.cpp index 476b21d0d6..681bd3b0e4 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingMetaData.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingMetaData.cpp @@ -152,19 +152,19 @@ namespace ScriptCanvas { if (azrtti_istypeof(execution->GetId().m_node)) { - return MetaDataPtr(aznew FormatStringMetaData()); + return AZStd::make_shared(); } else if (azrtti_istypeof(execution->GetId().m_node)) { - return MetaDataPtr(aznew PrintMetaData()); + return AZStd::make_shared(); } else if (azrtti_istypeof(execution->GetId().m_node)) { - return MetaDataPtr(aznew MathExpressionMetaData()); + return AZStd::make_shared(); } else if (execution->GetSymbol() == Symbol::FunctionCall) { - return MetaDataPtr(aznew FunctionCallDefaultMetaData()); + return AZStd::make_shared(); } } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesDeclarations.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesDeclarations.cpp index 14f7a926b1..52f00af6c2 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesDeclarations.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesDeclarations.cpp @@ -15,6 +15,7 @@ namespace ScriptCanvas AZ_CVAR(bool, g_disableParseOnGraphValidation, false, {}, AZ::ConsoleFunctorFlags::Null, "In case parsing the graph is interfering with opening a graph, disable parsing on validation"); AZ_CVAR(bool, g_printAbstractCodeModel, true, {}, AZ::ConsoleFunctorFlags::Null, "Print out the Abstract Code Model at the end of parsing for debug purposes."); AZ_CVAR(bool, g_printAbstractCodeModelAtPrefabTime, false, {}, AZ::ConsoleFunctorFlags::Null, "Print out the Abstract Code Model at the end of parsing (at prefab time) for debug purposes."); + AZ_CVAR(bool, g_processingErrorsForUnitTestsEnabled, false, {}, AZ::ConsoleFunctorFlags::Null, "Enable AP processing errors on parse failure for unit tests."); AZ_CVAR(bool, g_saveRawTranslationOuputToFile, true, {}, AZ::ConsoleFunctorFlags::Null, "Save out the raw result of translation for debug purposes."); AZ_CVAR(bool, g_saveRawTranslationOuputToFileAtPrefabTime, false, {}, AZ::ConsoleFunctorFlags::Null, "Save out the raw result of translation (at prefab time) for debug purposes."); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesDeclarations.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesDeclarations.h index a6ce31d6e7..3caec6ddb5 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesDeclarations.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesDeclarations.h @@ -245,6 +245,7 @@ namespace ScriptCanvas AZ_CVAR_EXTERNED(bool, g_disableParseOnGraphValidation); AZ_CVAR_EXTERNED(bool, g_printAbstractCodeModel); AZ_CVAR_EXTERNED(bool, g_printAbstractCodeModelAtPrefabTime); + AZ_CVAR_EXTERNED(bool, g_processingErrorsForUnitTestsEnabled); AZ_CVAR_EXTERNED(bool, g_saveRawTranslationOuputToFile); AZ_CVAR_EXTERNED(bool, g_saveRawTranslationOuputToFileAtPrefabTime); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.cpp index 3d76883adc..59b924196b 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.cpp @@ -335,6 +335,11 @@ namespace ScriptCanvas return &m_datum; } + Datum& GraphVariable::ModDatum() + { + return m_datum; + } + void GraphVariable::ConfigureDatumView(ModifiableDatumView& datumView) { datumView.ConfigureView((*this)); @@ -493,14 +498,6 @@ namespace ScriptCanvas return m_sortPriority; } - bool GraphVariable::IsInFunction() const - { - AZ::Data::AssetType assetType = AZ::Data::AssetType::CreateNull(); - ScriptCanvas::GraphRequestBus::EventResult(assetType, m_scriptCanvasId, &ScriptCanvas::GraphRequests::GetAssetType); - - return assetType == azrtti_typeid(); - } - AZ::u32 GraphVariable::OnInitialValueSourceChanged() { VariableNotificationBus::Event(GetGraphScopedId(), &VariableNotifications::OnVariableInitialValueSourceChanged); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.h index dbc0a814c6..db83076f67 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.h @@ -127,6 +127,8 @@ namespace ScriptCanvas const Datum* GetDatum() const; + Datum& ModDatum(); + bool IsComponentProperty() const; void ConfigureDatumView(ModifiableDatumView& accessController); @@ -194,9 +196,7 @@ namespace ScriptCanvas choices.emplace_back(AZStd::make_pair(static_cast(VariableFlags::Scope::Function), s_ScopeNames[1])); return choices; } - - bool IsInFunction() const; - + void OnScopeTypedChanged(); AZ::u32 OnInitialValueSourceChanged(); void OnSortPriorityChanged(); diff --git a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake index 609f7cd454..77ccf7fda9 100644 --- a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake +++ b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake @@ -27,7 +27,9 @@ set(FILES Editor/Assets/ScriptCanvasAsset.cpp Editor/Include/ScriptCanvas/Assets/ScriptCanvasAssetBus.h Editor/Include/ScriptCanvas/Assets/ScriptCanvasAssetTypes.h + Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h Editor/Include/ScriptCanvas/Assets/ScriptCanvasAssetHandler.h + Editor/Assets/ScriptCanvasFileHandling.cpp Editor/Assets/ScriptCanvasAssetHandler.cpp Editor/Assets/ScriptCanvasAssetHolder.h Editor/Assets/ScriptCanvasAssetHolder.cpp @@ -55,6 +57,8 @@ set(FILES Editor/Components/EditorGraphVariableManagerComponent.cpp Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h Editor/Components/EditorScriptCanvasComponent.cpp + Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponentSerializer.h + Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponentSerializer.cpp Editor/Components/IconComponent.h Editor/Components/IconComponent.cpp Editor/Include/ScriptCanvas/GraphCanvas/DynamicSlotBus.h @@ -178,6 +182,8 @@ set(FILES Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.h Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp Editor/View/Widgets/ScriptCanvasNodePaletteToolbar.ui + Editor/View/Widgets/SourceHandlePropertyAssetCtrl.h + Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp Editor/View/Widgets/WidgetBus.h Editor/View/Widgets/DataTypePalette/DataTypePaletteModel.cpp Editor/View/Widgets/DataTypePalette/DataTypePaletteModel.h diff --git a/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_VM.cpp b/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_VM.cpp index 2a20ca84df..2c455d80f5 100644 --- a/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_VM.cpp +++ b/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_VM.cpp @@ -25,126 +25,6 @@ using namespace ScriptCanvasTests; using namespace TestNodes; using namespace ScriptCanvas::Execution; -// TODO: This fails to compile on Linux only -//ScriptCanvas::Grammar::SubgraphInterface* CreateExecutionMap(AZ::BehaviorContext& behaviorContext) -//{ -// using namespace ScriptCanvas; -// using namespace ScriptCanvas::Grammar; -// -// auto ins = CreateInsFromBehaviorContextMethods("TestNodeableObject", behaviorContext, { "Branch" } ); -// auto branchOutVoidTrue = CreateOut("BranchTrue", { "condition", "message" }); -// auto branchOutVoidFalse = CreateOut("BranchFalse", { "condition", "message", "vector" }); -// -// auto branchOut = FindInByName("Branch", ins); -// -// EXPECT_NE(branchOut, nullptr); -// if (branchOut) -// { -// branchOut->outs.emplace_back(AZStd::move(branchOutVoidTrue)); -// branchOut->outs.emplace_back(AZStd::move(branchOutVoidFalse)); -// } -// -// return aznew SubgraphInterface(AZStd::move(ins)); -//} - - -TEST_F(ScriptCanvasTestFixture, TestLuaObjectOrientation) -{ - using namespace ScriptCanvas; - using namespace ScriptCanvas::Grammar; - - AZ::ScriptContext sc; - sc.BindTo(m_behaviorContext); - RegisterAPI(sc.NativeContext()); - EXPECT_TRUE(sc.Execute( - R"LUA( - -assert(Nodeable ~= nil, 'Nodeable was nill') -assert(Nodeable.__call ~= nil, 'Nodeable.__call was nil') -assert(type(Nodeable.__call) == 'function', 'Nodeable.__call was not a function') - -local nodeable = Nodeable() -assert(nodeable ~= nil, 'nodeable was nil') -assert(type(nodeable) == "userdata", 'nodeable not userdata') - -local SubGraph = {} -SubGraph.s_name = "SubGraphery" -SubGraph.s_createdCount = 0 -function SubGraph:IncrementCreated() - SubGraph.s_createdCount = 1 + SubGraph.s_createdCount -end - -setmetatable(SubGraph, { __index = Nodeable }) -- exposed through BehaviorContext -local SubGraphInstanceMetatable = { __index = SubGraph } - -assert(getmetatable(SubGraph).__index == Nodeable, 'getmetatable(SubGraph).__index = Nodeable') -assert(type(getmetatable(SubGraph).__index) == 'table', "type(getmetatable(SubGraph).__index) ~= 'table'") - -function SubGraph.new() -- Add executionState input here and to Nodeable() - -- now individual instance values can be initialized - local instance = OverrideNodeableMetatable(Nodeable(), SubGraphInstanceMetatable) - assert(type(instance.s_createdCount) == 'number', 'subgraph.s_createdCount was not a number') - instance:IncrementCreated() - instance.name = 'SubGraph '..tostring(instance.s_createdCount) - return instance -end - -function SubGraph.newTable() -- Add executionState input here and to Nodeable() - -- now individual instance values can be initialized - local instance = setmetatable({}, SubGraphInstanceMetatable) - -- assert(getmetatable(instance) == SubGraphInstanceMetatable, "subgraphT") - assert(type(instance.s_createdCount) == 'number', 'subgraphT.s_createdCount was not a number') - instance:IncrementCreated() - instance.name = 'SubGraph '..tostring(instance.s_createdCount) - return instance -end - -function SubGraph:Foo() - return "I, " .. tostring(self.name) .. ", am a user function" -end - -local subgraphT = SubGraph.newTable() -assert(subgraphT ~= nil, "subgraphT was nil") -assert(type(subgraphT) == 'table', 'subgraphT was not a table') -assert(type(subgraphT.IsActive)== 'function', "subgraphT IsActive was not a function") -assert(type(subgraphT.Foo) == 'function', 'subgraphT was not a function') -local subgraphTResult = subgraphT:Foo() -assert(subgraphTResult == "I, SubGraph 1, am a user function", 'subgraphT did not return the right results:' .. tostring(subgraphTResult)) -assert(subgraphT.s_createdCount == 1, "subgraphT created count was not one: ".. tostring(subgraphT.s_createdCount)) -subgraphT = SubGraph.newTable() -assert(subgraphT.s_createdCount == 2, "subgraphT created count was not two: ".. tostring(subgraphT.s_createdCount)) - -local subgraph = SubGraph.new() -assert(subgraph ~= nil, "subgraph was nil") -assert(type(subgraph) == 'userdata', 'was not userdata') -assert(type(subgraph.IsActive)== 'function', "IsActive was not a function") -assert(not subgraph.IsActive(subgraph), "did not inherit properly") -assert(not subgraph:IsActive(), "did not inherit properly") -assert(type(subgraph.Foo) == 'function', 'was not a function') -local subgraphResult = subgraph:Foo() -assert(subgraphResult == "I, SubGraph 3, am a user function", 'subgraph:Foo() did not return the right results: ' .. tostring(subgraphResult)) -assert(subgraph.s_createdCount == 3, "created count was not three: "..tostring(subgraph.s_createdCount)) - -local subgraph2 = SubGraph.new() -assert(subgraph2 ~= nil, "subgraph2 was nil") -assert(type(subgraph2) == 'userdata', 'subgraph2 was not userdata') -assert(type(subgraph2.IsActive)== 'function', "subgraph2 IsActive was not a function") -assert(not subgraph2.IsActive(subgraph2), "subgraph2 did not inherit properly") -assert(not subgraph2:IsActive(), "subgraph2 did not inherit properly") -assert(type(subgraph2.Foo) == 'function', 'subgraph2 was not a function') -local subgraph2Result = subgraph2:Foo() -assert(subgraph2Result == "I, SubGraph 4, am a user function", 'subgraph2:Foo() did not return the right results: ' .. tostring(subgraph2Result)) -assert(subgraph2.s_createdCount == 4, "created count was not three: "..tostring(subgraph2.s_createdCount)) - -return SubGraph - -)LUA" -)); - -} - - -// // TEST_F(ScriptCanvasTestFixture, NativeNodeableStack) // { // TestNodeableObject nodeable;