file save finished, not tested
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
This commit is contained in:
@@ -686,7 +686,7 @@ namespace ScriptCanvasEditor
|
||||
|
||||
void EditorGraphUpgradeMachine::OnComplete(IState::ExitStatus exitStatus)
|
||||
{
|
||||
UpgradeNotifications::Bus::Broadcast(&UpgradeNotifications::OnGraphUpgradeComplete, m_asset, exitStatus == IState::ExitStatus::Skipped);
|
||||
UpgradeNotificationsBus::Broadcast(&UpgradeNotifications::OnGraphUpgradeComplete, m_asset, exitStatus == IState::ExitStatus::Skipped);
|
||||
|
||||
m_asset = {};
|
||||
}
|
||||
|
||||
@@ -236,8 +236,6 @@ namespace ScriptCanvasEditor
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
|
||||
|
||||
using Bus = AZ::EBus<UpgradeNotifications>;
|
||||
|
||||
virtual void OnUpgradeStart() {}
|
||||
virtual void OnUpgradeComplete() {}
|
||||
virtual void OnUpgradeCancelled() {}
|
||||
@@ -245,6 +243,5 @@ namespace ScriptCanvasEditor
|
||||
virtual void OnGraphUpgradeComplete(AZ::Data::Asset<AZ::Data::AssetData>&, bool skipped = false) { (void)skipped; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
using UpgradeNotificationsBus = AZ::EBus<UpgradeNotifications>;
|
||||
}
|
||||
|
||||
@@ -829,12 +829,12 @@ namespace ScriptCanvasEditor
|
||||
NodePaletteModel::NodePaletteModel()
|
||||
: m_paletteId(AZ::Entity::MakeId())
|
||||
{
|
||||
UpgradeNotifications::Bus::Handler::BusConnect();
|
||||
UpgradeNotificationsBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
NodePaletteModel::~NodePaletteModel()
|
||||
{
|
||||
UpgradeNotifications::Bus::Handler::BusDisconnect();
|
||||
UpgradeNotificationsBus::Handler::BusDisconnect();
|
||||
|
||||
DisconnectLambdas();
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace ScriptCanvasEditor
|
||||
|
||||
class NodePaletteModel
|
||||
: public GraphCanvas::CategorizerInterface
|
||||
, UpgradeNotifications::Bus::Handler
|
||||
, UpgradeNotificationsBus::Handler
|
||||
{
|
||||
public:
|
||||
typedef AZStd::unordered_map< ScriptCanvas::NodeTypeIdentifier, NodePaletteModelInformation* > NodePaletteRegistry;
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace ScriptCanvasEditor
|
||||
, m_assetModel(assetModel)
|
||||
, m_categorizer(nodePaletteModel)
|
||||
{
|
||||
UpgradeNotifications::Bus::Handler::BusConnect();
|
||||
UpgradeNotificationsBus::Handler::BusConnect();
|
||||
|
||||
if (m_assetModel)
|
||||
{
|
||||
@@ -166,7 +166,7 @@ namespace ScriptCanvasEditor
|
||||
|
||||
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
|
||||
AZ::Data::AssetBus::MultiHandler::BusDisconnect();
|
||||
UpgradeNotifications::Bus::Handler::BusDisconnect();
|
||||
UpgradeNotificationsBus::Handler::BusDisconnect();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace ScriptCanvasEditor
|
||||
: public GraphCanvas::NodePaletteTreeItem
|
||||
, AzFramework::AssetCatalogEventBus::Handler
|
||||
, AZ::Data::AssetBus::MultiHandler
|
||||
, UpgradeNotifications::Bus::Handler
|
||||
, UpgradeNotificationsBus::Handler
|
||||
, AZ::SystemTickBus::Handler
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -98,19 +98,19 @@ namespace ScriptCanvasEditor
|
||||
|
||||
class ScriptCanvasAssetBrowserModel
|
||||
: public AzToolsFramework::AssetBrowser::AssetBrowserFilterModel
|
||||
, private UpgradeNotifications::Bus::Handler
|
||||
, private UpgradeNotificationsBus::Handler
|
||||
{
|
||||
public:
|
||||
|
||||
explicit ScriptCanvasAssetBrowserModel(QObject* parent = nullptr)
|
||||
: AzToolsFramework::AssetBrowser::AssetBrowserFilterModel(parent)
|
||||
{
|
||||
UpgradeNotifications::Bus::Handler::BusConnect();
|
||||
UpgradeNotificationsBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
~ScriptCanvasAssetBrowserModel() override
|
||||
{
|
||||
UpgradeNotifications::Bus::Handler::BusDisconnect();
|
||||
UpgradeNotificationsBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void OnUpgradeStart() override
|
||||
|
||||
@@ -52,9 +52,9 @@ namespace ScriptCanvasEditor
|
||||
m_view->tableWidget->setColumnWidth(3, 22);
|
||||
m_view->textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded);
|
||||
m_view->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn);
|
||||
connect(m_view->scanButton, &QPushButton::pressed, this, &Controller::OnScanButtonPress);
|
||||
connect(m_view->closeButton, &QPushButton::pressed, this, &Controller::OnCloseButtonPress);
|
||||
connect(m_view->upgradeAllButton, &QPushButton::pressed, this, &Controller::OnUpgradeButtonPress);
|
||||
connect(m_view->scanButton, &QPushButton::pressed, this, &Controller::OnButtonPressScan);
|
||||
connect(m_view->closeButton, &QPushButton::pressed, this, &Controller::OnButtonPressClose);
|
||||
connect(m_view->upgradeAllButton, &QPushButton::pressed, this, &Controller::OnButtonPressUpgrade);
|
||||
m_view->progressBar->setValue(0);
|
||||
m_view->progressBar->setVisible(false);
|
||||
|
||||
@@ -87,12 +87,12 @@ namespace ScriptCanvasEditor
|
||||
LogBus::Broadcast(&LogTraits::Clear);
|
||||
}
|
||||
|
||||
void Controller::OnCloseButtonPress()
|
||||
void Controller::OnButtonPressClose()
|
||||
{
|
||||
reject();
|
||||
}
|
||||
|
||||
void Controller::OnScanButtonPress()
|
||||
void Controller::OnButtonPressScan()
|
||||
{
|
||||
// \todo move to another file
|
||||
auto isUpToDate = [this](AZ::Data::Asset<AZ::Data::AssetData> asset)
|
||||
@@ -128,6 +128,148 @@ namespace ScriptCanvasEditor
|
||||
ModelRequestsBus::Broadcast(&ModelRequestsTraits::Scan, config);
|
||||
}
|
||||
|
||||
void Controller::OnButtonPressUpgrade()
|
||||
{
|
||||
auto simpleUpdate = [this](AZ::Data::Asset<AZ::Data::AssetData> asset)
|
||||
{
|
||||
if (asset.GetType() == azrtti_typeid<ScriptCanvasAsset>())
|
||||
{
|
||||
ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs<ScriptCanvasAsset>();
|
||||
AZ_Assert(scriptCanvasAsset, "Unable to get the asset of ScriptCanvasAsset, but received type: %s"
|
||||
, azrtti_typeid<ScriptCanvasAsset>().template ToString<AZStd::string>().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<ScriptCanvasEditor::Graph>();
|
||||
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());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto onReadyOnlyFile = [this]()->bool
|
||||
{
|
||||
int result = QMessageBox::No;
|
||||
QMessageBox mb
|
||||
( 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?")
|
||||
, QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No
|
||||
, this);
|
||||
result = mb.exec();
|
||||
return result == QMessageBox::YesToAll;
|
||||
};
|
||||
|
||||
ModifyConfiguration config;
|
||||
config.modification = simpleUpdate;
|
||||
config.onReadOnlyFile = onReadyOnlyFile;
|
||||
config.backupGraphBeforeModification = m_view->makeBackupCheckbox->isChecked();
|
||||
ModelRequestsBus::Broadcast(&ModelRequestsTraits::Modify, config);
|
||||
}
|
||||
|
||||
void Controller::OnUpgradeModificationBegin([[maybe_unused]] const ModifyConfiguration& config, const AZ::Data::AssetInfo& info)
|
||||
{
|
||||
QList<QTableWidgetItem*> items = m_view->tableWidget->findItems(info.m_relativePath.c_str(), Qt::MatchFlag::MatchExactly);
|
||||
if (!items.isEmpty())
|
||||
{
|
||||
for (auto* item : items)
|
||||
{
|
||||
int row = item->row();
|
||||
SetRowBusy(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::OnUpgradeModificationEnd
|
||||
( [[maybe_unused]] const ModifyConfiguration& config
|
||||
, const AZ::Data::AssetInfo& info
|
||||
, ModificationResult result)
|
||||
{
|
||||
if (result.errorMessage.empty())
|
||||
{
|
||||
VE_LOG("Successfully modified %s", result.assetInfo.m_relativePath.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
VE_LOG("Failed to modify %s: %s", result.assetInfo.m_relativePath.c_str(), result.errorMessage.data());
|
||||
}
|
||||
|
||||
QList<QTableWidgetItem*> items = m_view->tableWidget->findItems(info.m_relativePath.c_str(), Qt::MatchFlag::MatchExactly);
|
||||
if (!items.isEmpty())
|
||||
{
|
||||
for (auto* item : items)
|
||||
{
|
||||
int row = item->row();
|
||||
|
||||
if (result.errorMessage.empty())
|
||||
{
|
||||
SetRowSucceeded(row);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetRowFailed(row, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_view->progressBar->setVisible(true);
|
||||
++m_handledAssetCount;
|
||||
m_view->progressBar->setValue(m_handledAssetCount);
|
||||
}
|
||||
|
||||
void Controller::OnGraphUpgradeComplete(AZ::Data::Asset<AZ::Data::AssetData>& asset, bool skipped)
|
||||
{
|
||||
ModificationResult result;
|
||||
result.asset = asset;
|
||||
AZ::Data::AssetCatalogRequestBus::BroadcastResult
|
||||
( result.assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, asset.GetId());
|
||||
|
||||
if (skipped)
|
||||
{
|
||||
result.errorMessage = "Failed in editor upgrade state machine - check logs";
|
||||
}
|
||||
|
||||
ModificationNotificationsBus::Broadcast(&ModificationNotificationsTraits::ModificationComplete, result);
|
||||
}
|
||||
|
||||
void Controller::OnScanBegin(size_t assetCount)
|
||||
{
|
||||
m_handledAssetCount = 0;
|
||||
@@ -264,68 +406,6 @@ namespace ScriptCanvasEditor
|
||||
OnScannedGraph(info, Filtered::No);
|
||||
}
|
||||
|
||||
void Controller::OnUpgradeButtonPress()
|
||||
{
|
||||
auto simpleUpdate = [this](AZ::Data::Asset<AZ::Data::AssetData> asset)
|
||||
{
|
||||
if (asset.GetType() == azrtti_typeid<ScriptCanvasAsset>())
|
||||
{
|
||||
ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs<ScriptCanvasAsset>();
|
||||
AZ_Assert(scriptCanvasAsset, "Unable to get the asset of ScriptCanvasAsset, but received type: %s"
|
||||
, azrtti_typeid<ScriptCanvasAsset>().template ToString<AZStd::string>().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<ScriptCanvasEditor::Graph>();
|
||||
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());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ModifyConfiguration config;
|
||||
config.modification = simpleUpdate;
|
||||
config.backupGraphBeforeModification = m_view->makeBackupCheckbox->isChecked();
|
||||
ModelRequestsBus::Broadcast(&ModelRequestsTraits::Modify, config);
|
||||
}
|
||||
|
||||
void Controller::OnUpgradeBegin
|
||||
( const ModifyConfiguration& config
|
||||
, [[maybe_unused]] const AZStd::vector<AZ::Data::AssetInfo>& assets)
|
||||
@@ -359,8 +439,13 @@ namespace ScriptCanvasEditor
|
||||
m_view->spinner->SetBusyIconSize(16);
|
||||
}
|
||||
|
||||
void Controller::OnUpgradeComplete()
|
||||
void Controller::OnUpgradeComplete(const ModificationResults& result)
|
||||
{
|
||||
QString spinnerText = QStringLiteral("Upgrade Complete - ");
|
||||
spinnerText.append(QString::asprintf(" - Upgraded: %zu, Failed: %zu"
|
||||
, result.m_successes.size()
|
||||
, result.m_failures.size()));
|
||||
m_view->spinner->SetText(spinnerText);
|
||||
SetSpinnerIsBusy(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace ScriptCanvasEditor
|
||||
//! Handles display change notifications, handles state change notifications, sends control requests
|
||||
class Controller
|
||||
: public AzQtComponents::StyledDialog
|
||||
, private UpgradeNotifications::Bus::Handler
|
||||
, private UpgradeNotificationsBus::Handler
|
||||
, private ModelNotificationsBus::Handler
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -62,10 +62,12 @@ namespace ScriptCanvasEditor
|
||||
|
||||
void AddLogEntries();
|
||||
|
||||
void OnCloseButtonPress();
|
||||
void OnScanButtonPress();
|
||||
void OnUpgradeButtonPress();
|
||||
void OnButtonPressClose();
|
||||
void OnButtonPressScan();
|
||||
void OnButtonPressUpgrade();
|
||||
|
||||
void OnGraphUpgradeComplete(AZ::Data::Asset<AZ::Data::AssetData>&, bool skipped) override;
|
||||
|
||||
void OnScanBegin(size_t assetCount) override;
|
||||
void OnScanComplete(const ScanResult& result) override;
|
||||
void OnScanFilteredGraph(const AZ::Data::AssetInfo& info) override;
|
||||
@@ -77,7 +79,7 @@ namespace ScriptCanvasEditor
|
||||
|
||||
// for single operation UI updates, just check the assets size, or note it on the request
|
||||
void OnUpgradeBegin(const ModifyConfiguration& config, const AZStd::vector<AZ::Data::AssetInfo>& assets) override;
|
||||
void OnUpgradeComplete() override;
|
||||
void OnUpgradeComplete(const ModificationResults& results) override;
|
||||
void OnUpgradeDependenciesGathered(const AZ::Data::AssetInfo& info, Result result) override;
|
||||
void OnUpgradeDependencySortBegin
|
||||
( const ModifyConfiguration& config
|
||||
@@ -86,6 +88,8 @@ namespace ScriptCanvasEditor
|
||||
( const ModifyConfiguration& config
|
||||
, const AZStd::vector<AZ::Data::AssetInfo>& assets
|
||||
, const AZStd::vector<size_t>& 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 SetSpinnerIsBusy(bool isBusy);
|
||||
void SetRowBusy(int index);
|
||||
|
||||
@@ -6,8 +6,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Asset/AssetManagerBus.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/IO/FileIOEventBus.h>
|
||||
#include <AzFramework/Asset/AssetSystemBus.h>
|
||||
#include <AzFramework/IO/FileOperations.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/SourceControl/SourceControlAPI.h>
|
||||
#include <Editor/View/Windows/Tools/UpgradeTool/FileSaver.h>
|
||||
#include <ScriptCanvas/Assets/ScriptCanvasAssetHandler.h>
|
||||
|
||||
namespace FileSaverCpp
|
||||
{
|
||||
@@ -44,6 +51,183 @@ namespace ScriptCanvasEditor
|
||||
{
|
||||
namespace VersionExplorer
|
||||
{
|
||||
FileSaver::FileSaver
|
||||
( AZStd::function<bool()> onReadOnlyFile
|
||||
, AZStd::function<void(const FileSaveResult& result)> onComplete)
|
||||
: m_onReadOnlyFile(onReadOnlyFile)
|
||||
, m_onComplete(onComplete)
|
||||
{}
|
||||
|
||||
void FileSaver::PerformMove
|
||||
( AZStd::string tmpFileName
|
||||
, AZStd::string target
|
||||
, size_t remainingAttempts)
|
||||
{
|
||||
FileSaverCpp::FileEventHandler fileEventHandler;
|
||||
|
||||
if (remainingAttempts == 0)
|
||||
{
|
||||
AZ::SystemTickBus::QueueFunction([this, tmpFileName]()
|
||||
{
|
||||
FileSaveResult result;
|
||||
result.fileSaveError = "Failed to move updated file from temporary location to tmpFileName destination";
|
||||
result.tempFileRemovalError = RemoveTempFile(tmpFileName);
|
||||
m_onComplete(result);
|
||||
});
|
||||
}
|
||||
else if (remainingAttempts == 2)
|
||||
{
|
||||
auto streamer = AZ::Interface<AZ::IO::IStreamer>::Get();
|
||||
// before the last attempt, flush all the caches
|
||||
AZ::IO::FileRequestPtr flushRequest = streamer->FlushCaches();
|
||||
streamer->SetRequestCompleteCallback(flushRequest
|
||||
, [this, remainingAttempts, tmpFileName, target]([[maybe_unused]] AZ::IO::FileRequestHandle request)
|
||||
{
|
||||
// One last try
|
||||
AZ::SystemTickBus::QueueFunction(
|
||||
[this, remainingAttempts, tmpFileName, target]() { PerformMove(tmpFileName, target, remainingAttempts - 1); });
|
||||
});
|
||||
streamer->QueueRequest(flushRequest);
|
||||
}
|
||||
else
|
||||
{
|
||||
// the actual move attempt
|
||||
auto moveResult = AZ::IO::SmartMove(tmpFileName.c_str(), target.c_str());
|
||||
if (moveResult.GetResultCode() == AZ::IO::ResultCode::Success)
|
||||
{
|
||||
auto streamer = AZ::Interface<AZ::IO::IStreamer>::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());
|
||||
AZ::SystemTickBus::QueueFunction([this, tmpFileName]()
|
||||
{
|
||||
FileSaveResult result;
|
||||
result.tempFileRemovalError = RemoveTempFile(tmpFileName);
|
||||
m_onComplete(result);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to tmpFileName destination failed: %s, trying again", target.c_str());
|
||||
auto streamer = AZ::Interface<AZ::IO::IStreamer>::Get();
|
||||
AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str());
|
||||
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); });
|
||||
});
|
||||
streamer->QueueRequest(flushRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileSaver::OnSourceFileReleased(AZ::Data::Asset<AZ::Data::AssetData> asset)
|
||||
{
|
||||
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 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.
|
||||
if (!AZ::IO::CreateTempFileName(fullPath.c_str(), tmpFileName))
|
||||
{
|
||||
FileSaveResult result;
|
||||
result.fileSaveError = "Failure to create temporary file name";
|
||||
m_onComplete(result);
|
||||
return;
|
||||
}
|
||||
|
||||
bool tempSavedSucceeded = false;
|
||||
AZ::IO::FileIOStream fileStream(tmpFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText);
|
||||
if (fileStream.IsOpen())
|
||||
{
|
||||
if (asset.GetType() == azrtti_typeid<ScriptCanvasEditor::ScriptCanvasAsset>())
|
||||
{
|
||||
ScriptCanvasEditor::ScriptCanvasAssetHandler handler;
|
||||
tempSavedSucceeded = handler.SaveAssetData(asset, &fileStream);
|
||||
}
|
||||
|
||||
fileStream.Close();
|
||||
}
|
||||
|
||||
if (!tempSavedSucceeded)
|
||||
{
|
||||
FileSaveResult result;
|
||||
result.fileSaveError = "Save asset data to temporary file failed";
|
||||
m_onComplete(result);
|
||||
return;
|
||||
}
|
||||
|
||||
AzToolsFramework::SourceControlCommandBus::Broadcast
|
||||
( &AzToolsFramework::SourceControlCommandBus::Events::RequestEdit
|
||||
, fullPath.c_str()
|
||||
, true
|
||||
, [this, fullPath, tmpFileName]([[maybe_unused]] bool success, const AzToolsFramework::SourceControlFileInfo& info)
|
||||
{
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
AZStd::string FileSaver::RemoveTempFile(AZStd::string_view tempFile)
|
||||
{
|
||||
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
|
||||
if (!fileIO)
|
||||
{
|
||||
return "GraphUpgradeComplete: No FileIO instance";
|
||||
}
|
||||
|
||||
if (fileIO->Exists(tempFile.data()) && !fileIO->Remove(tempFile.data()))
|
||||
{
|
||||
return AZStd::string::format("Failed to remove temporary file: %s", tempFile.data());
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void FileSaver::Save(AZ::Data::Asset<AZ::Data::AssetData> asset)
|
||||
{
|
||||
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);
|
||||
|
||||
if (!fullPathFound)
|
||||
{
|
||||
FileSaveResult result;
|
||||
result.fileSaveError = "Full source path not found";
|
||||
m_onComplete(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto streamer = AZ::Interface<AZ::IO::IStreamer>::Get();
|
||||
AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(fullPath);
|
||||
streamer->SetRequestCompleteCallback(flushRequest, [this, asset]([[maybe_unused]] AZ::IO::FileRequestHandle request)
|
||||
{
|
||||
this->OnSourceFileReleased(asset);
|
||||
});
|
||||
streamer->QueueRequest(flushRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,35 @@ namespace ScriptCanvasEditor
|
||||
{
|
||||
namespace VersionExplorer
|
||||
{
|
||||
struct FileSaveResult
|
||||
{
|
||||
AZStd::string fileSaveError;
|
||||
AZStd::string tempFileRemovalError;
|
||||
};
|
||||
|
||||
class FileSaver
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(FileSaver, AZ::SystemAllocator, 0);
|
||||
|
||||
FileSaver
|
||||
( AZStd::function<bool()> onReadOnlyFile
|
||||
, AZStd::function<void(const FileSaveResult& result)> onComplete);
|
||||
|
||||
void Save(AZ::Data::Asset<AZ::Data::AssetData> asset);
|
||||
|
||||
private:
|
||||
AZStd::function<void(const FileSaveResult& result)> m_onComplete;
|
||||
AZStd::function<bool()> m_onReadOnlyFile;
|
||||
|
||||
void OnSourceFileReleased(AZ::Data::Asset<AZ::Data::AssetData> asset);
|
||||
|
||||
void PerformMove
|
||||
( AZStd::string source
|
||||
, AZStd::string target
|
||||
, size_t remainingAttempts);
|
||||
|
||||
AZStd::string RemoveTempFile(AZStd::string_view tempFile);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace ScriptCanvasEditor
|
||||
|
||||
void Model::OnModificationComplete()
|
||||
{
|
||||
ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanComplete, m_scanner->GetResult());
|
||||
ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeComplete, m_modifier->GetResult());
|
||||
m_modifier.reset();
|
||||
m_scanner.reset();
|
||||
Idle();
|
||||
|
||||
@@ -57,7 +57,8 @@ namespace ScriptCanvasEditor
|
||||
|
||||
State m_state = State::Idle;
|
||||
Log m_log;
|
||||
|
||||
|
||||
// these two are managed by the same class because the modifer will only operate on the results of the scanner
|
||||
AZStd::unique_ptr<Modifier> m_modifier;
|
||||
AZStd::unique_ptr<Scanner> m_scanner;
|
||||
AZStd::unique_ptr<ScriptCanvas::Grammar::SettingsCache> m_settingsCache;
|
||||
|
||||
@@ -17,11 +17,27 @@ namespace ScriptCanvasEditor
|
||||
struct ModifyConfiguration
|
||||
{
|
||||
AZStd::function<void(AZ::Data::Asset<AZ::Data::AssetData>)> modification;
|
||||
AZStd::function<bool()> onReadOnlyFile;
|
||||
bool modifySingleAsset = false;
|
||||
bool backupGraphBeforeModification = false;
|
||||
bool successfulDependencyUpgradeRequired = true;
|
||||
};
|
||||
|
||||
struct ModificationResult
|
||||
{
|
||||
AZ::Data::Asset<AZ::Data::AssetData> asset;
|
||||
AZ::Data::AssetInfo assetInfo;
|
||||
AZStd::string errorMessage;
|
||||
};
|
||||
|
||||
class ModificationNotificationsTraits
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
virtual void ModificationComplete(const ModificationResult& result) = 0;
|
||||
};
|
||||
using ModificationNotificationsBus = AZ::EBus<ModificationNotificationsTraits>;
|
||||
|
||||
struct ScanConfiguration
|
||||
{
|
||||
AZStd::function<bool(AZ::Data::Asset<AZ::Data::AssetData>)> filter;
|
||||
@@ -37,9 +53,10 @@ namespace ScriptCanvasEditor
|
||||
};
|
||||
using ModelRequestsBus = AZ::EBus<ModelRequestsTraits>;
|
||||
|
||||
struct ModificationResult
|
||||
struct ModificationResults
|
||||
{
|
||||
|
||||
AZStd::vector<AZ::Data::AssetInfo> m_successes;
|
||||
AZStd::vector<ModificationResult> m_failures;
|
||||
};
|
||||
|
||||
struct ScanResult
|
||||
@@ -67,9 +84,7 @@ namespace ScriptCanvasEditor
|
||||
virtual void OnScanUnFilteredGraph(const AZ::Data::AssetInfo& info) = 0;
|
||||
|
||||
virtual void OnUpgradeBegin(const ModifyConfiguration& config, const AZStd::vector<AZ::Data::AssetInfo>& assets) = 0;
|
||||
virtual void OnUpgradeComplete() = 0;
|
||||
// virtual void OnUpgradeModificationBegin(const ModifyConfiguration& config) = 0;
|
||||
// virtual void OnUpgradeModification(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info, Result result) = 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
|
||||
@@ -78,6 +93,8 @@ namespace ScriptCanvasEditor
|
||||
( const ModifyConfiguration& config
|
||||
, const AZStd::vector<AZ::Data::AssetInfo>& assets
|
||||
, const AZStd::vector<size_t>& 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;
|
||||
};
|
||||
using ModelNotificationsBus = AZ::EBus<ModelNotificationsTraits>;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace ScriptCanvasEditor
|
||||
, m_assets(assets)
|
||||
, m_onComplete(onComplete)
|
||||
{
|
||||
AZ_Assert(m_config.modification, "No modification function provided");
|
||||
ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeBegin, modification, m_assets);
|
||||
AZ::SystemTickBus::Handler::BusConnect();
|
||||
}
|
||||
@@ -52,6 +53,11 @@ namespace ScriptCanvasEditor
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
const ModificationResults& Modifier::GetResult() const
|
||||
{
|
||||
return m_results;
|
||||
}
|
||||
|
||||
void Modifier::GatherDependencies()
|
||||
{
|
||||
AZ::SerializeContext* serializeContext{};
|
||||
@@ -140,6 +146,84 @@ namespace ScriptCanvasEditor
|
||||
}
|
||||
}
|
||||
|
||||
void Modifier::ModificationComplete(const ModificationResult& result)
|
||||
{
|
||||
m_result = result;
|
||||
|
||||
if (result.errorMessage.empty())
|
||||
{
|
||||
SaveModifiedGraph(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReportModificationError(result.errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void Modifier::ModifyCurrentAsset()
|
||||
{
|
||||
m_result = {};
|
||||
m_result.assetInfo = GetCurrentAsset();
|
||||
|
||||
ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeModificationBegin, m_config, GetCurrentAsset());
|
||||
|
||||
if (auto asset = LoadAsset())
|
||||
{
|
||||
ModificationNotificationsBus::Handler::BusConnect();
|
||||
m_modifyState = ModifyState::InProgress;
|
||||
m_config.modification(asset);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReportModificationError("Failed to load during modification");
|
||||
}
|
||||
}
|
||||
|
||||
void Modifier::ModifyNextAsset()
|
||||
{
|
||||
ModelNotificationsBus::Broadcast
|
||||
( &ModelNotificationsTraits::OnUpgradeModificationEnd, m_config, GetCurrentAsset(), m_result);
|
||||
m_modifyState = ModifyState::Idle;
|
||||
++m_assetIndex;
|
||||
m_result = {};
|
||||
}
|
||||
|
||||
void Modifier::ReportModificationError(AZStd::string_view report)
|
||||
{
|
||||
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::OnFileSaveComplete(const FileSaveResult& result)
|
||||
{
|
||||
if (!result.tempFileRemovalError.empty())
|
||||
{
|
||||
VE_LOG
|
||||
( "Temporary file not removed for %s: %s"
|
||||
, m_result.assetInfo.m_relativePath.c_str()
|
||||
, result.tempFileRemovalError.c_str());
|
||||
}
|
||||
|
||||
m_fileSaver.reset();
|
||||
|
||||
if (result.fileSaveError.empty())
|
||||
{
|
||||
ReportModificationSuccess();
|
||||
}
|
||||
else
|
||||
{
|
||||
ReportModificationError(result.fileSaveError);
|
||||
}
|
||||
}
|
||||
|
||||
void Modifier::OnSystemTick()
|
||||
{
|
||||
switch (m_state)
|
||||
@@ -154,50 +238,13 @@ namespace ScriptCanvasEditor
|
||||
}
|
||||
}
|
||||
|
||||
const AZStd::unordered_set<size_t>* Modifier::Sorter::GetDependencies(size_t index) const
|
||||
void Modifier::SaveModifiedGraph(const ModificationResult& result)
|
||||
{
|
||||
auto iter = modifier->m_dependencies.find(index);
|
||||
return iter != modifier->m_dependencies.end() ? &iter->second : nullptr;
|
||||
}
|
||||
|
||||
void Modifier::Sorter::Sort()
|
||||
{
|
||||
for (size_t index = 0; index != modifier->m_assets.size(); ++index)
|
||||
{
|
||||
Visit(index);
|
||||
}
|
||||
}
|
||||
|
||||
void Modifier::Sorter::Visit(size_t index)
|
||||
{
|
||||
if (markedPermanent.contains(index))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (markedTemporary.contains(index))
|
||||
{
|
||||
AZ_Error
|
||||
( ScriptCanvas::k_VersionExplorerWindow.data()
|
||||
, false
|
||||
, "Modifier: Dependency sort has failed during, circular dependency detected for Asset: %s"
|
||||
, modifier->GetCurrentAsset().m_relativePath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
markedTemporary.insert(index);
|
||||
|
||||
if (auto dependencies = GetDependencies(index))
|
||||
{
|
||||
for (auto& dependency : *dependencies)
|
||||
{
|
||||
Visit(dependency);
|
||||
}
|
||||
}
|
||||
|
||||
markedTemporary.erase(index);
|
||||
markedPermanent.insert(index);
|
||||
modifier->m_dependencyOrderedAssetIndicies.push_back(index);
|
||||
m_modifyState = ModifyState::Saving;
|
||||
m_fileSaver = AZStd::make_unique<FileSaver>
|
||||
( m_config.onReadOnlyFile
|
||||
, [this](const FileSaveResult& result) { OnFileSaveComplete(result); });
|
||||
m_fileSaver->Save(result.asset);
|
||||
}
|
||||
|
||||
void Modifier::SortGraphsByDependencies()
|
||||
@@ -208,6 +255,11 @@ namespace ScriptCanvasEditor
|
||||
sorter.Sort();
|
||||
}
|
||||
|
||||
ModificationResults&& Modifier::TakeResult()
|
||||
{
|
||||
return AZStd::move(m_results);
|
||||
}
|
||||
|
||||
void Modifier::TickGatherDependencies()
|
||||
{
|
||||
if (m_assetIndex == 0)
|
||||
@@ -260,8 +312,69 @@ namespace ScriptCanvasEditor
|
||||
|
||||
void Modifier::TickUpdateGraph()
|
||||
{
|
||||
if (m_assetIndex == m_assets.size())
|
||||
{
|
||||
VE_LOG("Modifier: Complete.");
|
||||
AZ::SystemTickBus::Handler::BusDisconnect();
|
||||
|
||||
if (m_onComplete)
|
||||
{
|
||||
m_onComplete();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_modifyState == ModifyState::Idle)
|
||||
{
|
||||
ModifyCurrentAsset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const AZStd::unordered_set<size_t>* Modifier::Sorter::GetDependencies(size_t index) const
|
||||
{
|
||||
auto iter = modifier->m_dependencies.find(index);
|
||||
return iter != modifier->m_dependencies.end() ? &iter->second : nullptr;
|
||||
}
|
||||
|
||||
void Modifier::Sorter::Sort()
|
||||
{
|
||||
for (size_t index = 0; index != modifier->m_assets.size(); ++index)
|
||||
{
|
||||
Visit(index);
|
||||
}
|
||||
}
|
||||
|
||||
void Modifier::Sorter::Visit(size_t index)
|
||||
{
|
||||
if (markedPermanent.contains(index))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (markedTemporary.contains(index))
|
||||
{
|
||||
AZ_Error
|
||||
(ScriptCanvas::k_VersionExplorerWindow.data()
|
||||
, false
|
||||
, "Modifier: Dependency sort has failed during, circular dependency detected for Asset: %s"
|
||||
, modifier->GetCurrentAsset().m_relativePath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
markedTemporary.insert(index);
|
||||
|
||||
if (auto dependencies = GetDependencies(index))
|
||||
{
|
||||
for (auto& dependency : *dependencies)
|
||||
{
|
||||
Visit(dependency);
|
||||
}
|
||||
}
|
||||
|
||||
markedTemporary.erase(index);
|
||||
markedPermanent.insert(index);
|
||||
modifier->m_dependencyOrderedAssetIndicies.push_back(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ScriptCanvas/Core/Core.h>
|
||||
#include <Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <Editor/View/Windows/Tools/UpgradeTool/FileSaver.h>
|
||||
#include <Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h>
|
||||
#include <ScriptCanvas/Core/Core.h>
|
||||
|
||||
namespace ScriptCanvasEditor
|
||||
{
|
||||
@@ -18,6 +19,7 @@ namespace ScriptCanvasEditor
|
||||
{
|
||||
class Modifier
|
||||
: private AZ::SystemTickBus::Handler
|
||||
, private ModificationNotificationsBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(Modifier, AZ::SystemAllocator, 0);
|
||||
@@ -27,6 +29,9 @@ namespace ScriptCanvasEditor
|
||||
, AZStd::vector<AZ::Data::AssetInfo>&& assets
|
||||
, AZStd::function<void()> onComplete);
|
||||
|
||||
const ModificationResults& GetResult() const;
|
||||
ModificationResults&& TakeResult();
|
||||
|
||||
private:
|
||||
friend class Sorter;
|
||||
|
||||
@@ -48,7 +53,16 @@ namespace ScriptCanvasEditor
|
||||
ModifyingGraphs
|
||||
};
|
||||
|
||||
enum class ModifyState
|
||||
{
|
||||
Idle,
|
||||
InProgress,
|
||||
Saving,
|
||||
};
|
||||
|
||||
// the two states reside in this class because the modification is only complete if the new source file saves out
|
||||
State m_state = State::GatheringDependencies;
|
||||
ModifyState m_modifyState = ModifyState::Idle;
|
||||
size_t m_assetIndex = 0;
|
||||
AZStd::function<void()> m_onComplete;
|
||||
// asset infos in scanned order
|
||||
@@ -61,12 +75,21 @@ namespace ScriptCanvasEditor
|
||||
AZStd::vector<size_t> m_failures;
|
||||
ModifyConfiguration m_config;
|
||||
ModificationResult m_result;
|
||||
ModificationResults m_results;
|
||||
AZStd::unique_ptr<FileSaver> m_fileSaver;
|
||||
|
||||
void GatherDependencies();
|
||||
const AZ::Data::AssetInfo& GetCurrentAsset() const;
|
||||
AZStd::unordered_set<size_t>& GetOrCreateDependencyIndexSet();
|
||||
AZ::Data::Asset<AZ::Data::AssetData> LoadAsset();
|
||||
void ModifyCurrentAsset();
|
||||
void ModifyNextAsset();
|
||||
void ModificationComplete(const ModificationResult& result) override;
|
||||
void ReportModificationError(AZStd::string_view report);
|
||||
void ReportModificationSuccess();
|
||||
void SaveModifiedGraph(const ModificationResult& result);
|
||||
void SortGraphsByDependencies();
|
||||
void OnFileSaveComplete(const FileSaveResult& result);
|
||||
void OnSystemTick() override;
|
||||
void TickGatherDependencies();
|
||||
void TickUpdateGraph();
|
||||
|
||||
@@ -25,7 +25,6 @@ namespace ScriptCanvasEditor
|
||||
Scanner(const ScanConfiguration& config, AZStd::function<void()> onComplete);
|
||||
|
||||
const ScanResult& GetResult() const;
|
||||
|
||||
ScanResult&& TakeResult();
|
||||
|
||||
private:
|
||||
|
||||
Reference in New Issue
Block a user