You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
482 lines
18 KiB
C++
482 lines
18 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
|
|
#include "precompiled.h"
|
|
|
|
#include <AzCore/Serialization/SerializeContext.h>
|
|
#include <AzCore/Serialization/EditContext.h>
|
|
#include <AzCore/Jobs/JobFunction.h>
|
|
#include <AzCore/EBus/Results.h>
|
|
#include <AzCore/std/string/wildcard.h>
|
|
|
|
#include <AzFramework/Entity/EntityContextBus.h>
|
|
|
|
#include <AzToolsFramework/API/ViewPaneOptions.h>
|
|
#include <AzToolsFramework/UI/PropertyEditor/GenericComboBoxCtrl.h>
|
|
|
|
#include <GraphCanvas/GraphCanvasBus.h>
|
|
|
|
#include <Editor/SystemComponent.h>
|
|
|
|
#include <Editor/View/Windows/MainWindow.h>
|
|
#include <Editor/View/Dialogs/NewGraphDialog.h>
|
|
#include <Editor/View/Dialogs/SettingsDialog.h>
|
|
#include <Editor/Settings.h>
|
|
|
|
#include <ScriptCanvas/Bus/EditorScriptCanvasBus.h>
|
|
#include <ScriptCanvas/Core/Datum.h>
|
|
#include <ScriptCanvas/Data/DataRegistry.h>
|
|
#include <ScriptCanvas/Libraries/Libraries.h>
|
|
#include <ScriptCanvas/Variable/VariableCore.h>
|
|
#include <ScriptCanvas/Components/EditorGraph.h>
|
|
#include <ScriptCanvas/Components/EditorGraphVariableManagerComponent.h>
|
|
|
|
#include <LyViewPaneNames.h>
|
|
|
|
#include <QMenu>
|
|
#include <QMessageBox>
|
|
|
|
#include <ScriptCanvas/View/EditCtrls/GenericLineEditCtrl.h>
|
|
#include <Editor/Framework/ScriptCanvasGraphUtilities.h>
|
|
#include <AzToolsFramework/AssetBrowser/Entries/SourceAssetBrowserEntry.h>
|
|
|
|
#include <AzFramework/IO/FileOperations.h>
|
|
#include <AzCore/Serialization/Utils.h>
|
|
|
|
#include <ScriptCanvas/Asset/Functions/ScriptCanvasFunctionAsset.h>
|
|
|
|
namespace ScriptCanvasEditor
|
|
{
|
|
static const size_t cs_jobThreads = 1;
|
|
|
|
SystemComponent::SystemComponent()
|
|
{
|
|
AzToolsFramework::AssetSeedManagerRequests::Bus::Handler::BusConnect();
|
|
}
|
|
|
|
SystemComponent::~SystemComponent()
|
|
{
|
|
AzToolsFramework::UnregisterViewPane(LyViewPane::ScriptCanvas);
|
|
AzToolsFramework::EditorContextMenuBus::Handler::BusDisconnect();
|
|
AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect();
|
|
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
|
|
AzToolsFramework::AssetSeedManagerRequests::Bus::Handler::BusDisconnect();
|
|
}
|
|
|
|
void SystemComponent::Reflect(AZ::ReflectContext* context)
|
|
{
|
|
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
|
|
{
|
|
ScriptCanvasEditor::Settings::Reflect(serialize);
|
|
|
|
serialize->Class<SystemComponent, AZ::Component>()
|
|
->Version(0)
|
|
;
|
|
|
|
if (AZ::EditContext* ec = serialize->GetEditContext())
|
|
{
|
|
ec->Class<SystemComponent>("Script Canvas Editor", "Script Canvas Editor System Component")
|
|
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
|
->Attribute(AZ::Edit::Attributes::Category, "Scripting")
|
|
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
|
|
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
|
;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
|
{
|
|
provided.push_back(AZ_CRC("ScriptCanvasEditorService", 0x4fe2af98));
|
|
}
|
|
|
|
void SystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
|
{
|
|
(void)incompatible;
|
|
}
|
|
|
|
void SystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
|
{
|
|
required.push_back(AZ_CRC("MemoryService", 0x5c4d473c)); // AZ::JobManager needs the thread pool allocator
|
|
required.push_back(AZ_CRC("ScriptCanvasService", 0x41fd58f3));
|
|
required.push_back(GraphCanvas::GraphCanvasRequestsServiceId);
|
|
required.push_back(AZ_CRC("ScriptCanvasReflectService", 0xb3bfe139));
|
|
}
|
|
|
|
void SystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
|
|
{
|
|
(void)dependent;
|
|
}
|
|
|
|
void SystemComponent::Init()
|
|
{
|
|
AzToolsFramework::EditorEvents::Bus::Handler::BusConnect();
|
|
AzToolsFramework::EditorContextMenuBus::Handler::BusConnect();
|
|
}
|
|
|
|
void SystemComponent::Activate()
|
|
{
|
|
m_assetTracker.Activate();
|
|
AZ::JobManagerDesc jobDesc;
|
|
for (size_t i = 0; i < cs_jobThreads; ++i)
|
|
{
|
|
jobDesc.m_workerThreads.push_back({ static_cast<int>(i) });
|
|
}
|
|
m_jobManager = AZStd::make_unique<AZ::JobManager>(jobDesc);
|
|
m_jobContext = AZStd::make_unique<AZ::JobContext>(*m_jobManager);
|
|
|
|
PopulateEditorCreatableTypes();
|
|
|
|
AzToolsFramework::RegisterGenericComboBoxHandler<ScriptCanvas::VariableId>();
|
|
|
|
SystemRequestBus::Handler::BusConnect();
|
|
ScriptCanvasExecutionBus::Handler::BusConnect();
|
|
AzToolsFramework::EditorEvents::Bus::Handler::BusConnect();
|
|
AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect();
|
|
|
|
auto userSettings = AZ::UserSettings::CreateFind<EditorSettings::ScriptCanvasEditorSettings>(AZ_CRC("ScriptCanvasPreviewSettings", 0x1c5a2965), AZ::UserSettings::CT_LOCAL);
|
|
if (userSettings)
|
|
{
|
|
if (userSettings->m_showUpgradeDialog)
|
|
{
|
|
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
|
|
}
|
|
else
|
|
{
|
|
m_upgradeDisabled = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
|
|
}
|
|
}
|
|
|
|
void SystemComponent::NotifyRegisterViews()
|
|
{
|
|
QtViewOptions options;
|
|
options.canHaveMultipleInstances = false;
|
|
options.isPreview = true;
|
|
options.showInMenu = true;
|
|
|
|
AzToolsFramework::RegisterViewPane<ScriptCanvasEditor::MainWindow>(LyViewPane::ScriptCanvas, LyViewPane::CategoryTools, options);
|
|
}
|
|
|
|
void SystemComponent::Deactivate()
|
|
{
|
|
AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusDisconnect();
|
|
AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect();
|
|
ScriptCanvasExecutionBus::Handler::BusDisconnect();
|
|
SystemRequestBus::Handler::BusDisconnect();
|
|
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
|
|
|
|
m_jobContext.reset();
|
|
m_jobManager.reset();
|
|
m_assetTracker.Deactivate();
|
|
}
|
|
|
|
void SystemComponent::AddAsyncJob(AZStd::function<void()>&& jobFunc)
|
|
{
|
|
auto* asyncFunction = AZ::CreateJobFunction(AZStd::move(jobFunc), true, m_jobContext.get());
|
|
asyncFunction->Start();
|
|
}
|
|
|
|
void SystemComponent::GetEditorCreatableTypes(AZStd::unordered_set<ScriptCanvas::Data::Type>& outCreatableTypes)
|
|
{
|
|
outCreatableTypes.insert(m_creatableTypes.begin(), m_creatableTypes.end());
|
|
}
|
|
|
|
void SystemComponent::CreateEditorComponentsOnEntity(AZ::Entity* entity, const AZ::Data::AssetType& assetType)
|
|
{
|
|
if (entity)
|
|
{
|
|
auto graph = entity->CreateComponent<Graph>();
|
|
graph->SetAssetType(assetType);
|
|
|
|
entity->CreateComponent<EditorGraphVariableManagerComponent>(graph->GetScriptCanvasId());
|
|
}
|
|
}
|
|
|
|
void SystemComponent::PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags)
|
|
{
|
|
(void)point;
|
|
(void)flags;
|
|
|
|
AzToolsFramework::EntityIdList entitiesWithScriptCanvas;
|
|
|
|
AzToolsFramework::EntityIdList selectedEntities;
|
|
AzToolsFramework::EntityIdList highlightedEntities;
|
|
|
|
EBUS_EVENT_RESULT(selectedEntities,
|
|
AzToolsFramework::ToolsApplicationRequests::Bus,
|
|
GetSelectedEntities);
|
|
|
|
FilterForScriptCanvasEnabledEntities(selectedEntities, entitiesWithScriptCanvas);
|
|
|
|
EBUS_EVENT_RESULT(highlightedEntities,
|
|
AzToolsFramework::ToolsApplicationRequests::Bus,
|
|
GetHighlightedEntities);
|
|
|
|
FilterForScriptCanvasEnabledEntities(highlightedEntities, entitiesWithScriptCanvas);
|
|
|
|
if (!entitiesWithScriptCanvas.empty())
|
|
{
|
|
QMenu* scriptCanvasMenu = nullptr;
|
|
QAction* action = nullptr;
|
|
|
|
// For entities with script canvas component, create a context menu to open any existing script canvases within each selected entity.
|
|
for (const AZ::EntityId& entityId : entitiesWithScriptCanvas)
|
|
{
|
|
if (!scriptCanvasMenu)
|
|
{
|
|
menu->addSeparator();
|
|
scriptCanvasMenu = menu->addMenu(QObject::tr("Edit Script Canvas"));
|
|
scriptCanvasMenu->setEnabled(false);
|
|
menu->addSeparator();
|
|
}
|
|
|
|
AZ::Entity* entity = nullptr;
|
|
EBUS_EVENT_RESULT(entity, AZ::ComponentApplicationBus, FindEntity, entityId);
|
|
|
|
if (entity)
|
|
{
|
|
AZ::EBusAggregateResults<AZ::Data::AssetId> assetIds;
|
|
EditorContextMenuRequestBus::EventResult(assetIds, entity->GetId(), &EditorContextMenuRequests::GetAssetId);
|
|
|
|
if (!assetIds.values.empty())
|
|
{
|
|
QMenu* entityMenu = scriptCanvasMenu;
|
|
if (entitiesWithScriptCanvas.size() > 1)
|
|
{
|
|
scriptCanvasMenu->setEnabled(true);
|
|
entityMenu = scriptCanvasMenu->addMenu(entity->GetName().c_str());
|
|
entityMenu->setEnabled(false);
|
|
}
|
|
|
|
AZStd::unordered_set< AZ::Data::AssetId > usedIds;
|
|
|
|
for (const auto& assetId : assetIds.values)
|
|
{
|
|
if (!assetId.IsValid() || usedIds.count(assetId) != 0)
|
|
{
|
|
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);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SystemComponent::FilterForScriptCanvasEnabledEntities(AzToolsFramework::EntityIdList& sourceList, AzToolsFramework::EntityIdList& targetList)
|
|
{
|
|
for (const AZ::EntityId& entityId : sourceList)
|
|
{
|
|
if (entityId.IsValid())
|
|
{
|
|
if (EditorContextMenuRequestBus::FindFirstHandler(entityId))
|
|
{
|
|
if (targetList.end() == AZStd::find(targetList.begin(), targetList.end(), entityId))
|
|
{
|
|
targetList.push_back(entityId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
AzToolsFramework::AssetBrowser::SourceFileDetails SystemComponent::GetSourceFileDetails(const char* fullSourceFileName)
|
|
{
|
|
if (AZStd::wildcard_match("*.scriptcanvas", fullSourceFileName))
|
|
{
|
|
return AzToolsFramework::AssetBrowser::SourceFileDetails("Icons/AssetBrowser/ScriptCanvas_16.png");
|
|
}
|
|
|
|
// not one of our types.
|
|
return AzToolsFramework::AssetBrowser::SourceFileDetails();
|
|
}
|
|
|
|
void SystemComponent::AddSourceFileOpeners(const char* fullSourceFileName, [[maybe_unused]] const AZ::Uuid& sourceUUID, AzToolsFramework::AssetBrowser::SourceFileOpenerList& openers)
|
|
{
|
|
using namespace AzToolsFramework;
|
|
using namespace AzToolsFramework::AssetBrowser;
|
|
|
|
bool isScriptCanvasAsset = false;
|
|
ScriptCanvasAssetDescription scriptCanvasAssetDescription;
|
|
if (AZStd::wildcard_match(AZStd::string::format("*%s", scriptCanvasAssetDescription.GetExtensionImpl()).c_str(), fullSourceFileName))
|
|
{
|
|
isScriptCanvasAsset = true;
|
|
}
|
|
|
|
ScriptCanvasFunctionDescription scriptCanvasFunctionAssetDescription;
|
|
if (!isScriptCanvasAsset && AZStd::wildcard_match(AZStd::string::format("*%s", scriptCanvasFunctionAssetDescription.GetExtensionImpl()).c_str(), fullSourceFileName))
|
|
{
|
|
isScriptCanvasAsset = true;
|
|
}
|
|
|
|
if (isScriptCanvasAsset)
|
|
{
|
|
auto scriptCanvasEditorCallback = [this]([[maybe_unused]] const char* fullSourceFileNameInCall, const AZ::Uuid& sourceUUIDInCall)
|
|
{
|
|
AZ::Outcome<int, AZStd::string> openOutcome = AZ::Failure(AZStd::string());
|
|
const SourceAssetBrowserEntry* fullDetails = SourceAssetBrowserEntry::GetSourceByUuid(sourceUUIDInCall);
|
|
if (fullDetails)
|
|
{
|
|
AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas);
|
|
|
|
AzToolsFramework::EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::OpenViewPane, "Script Canvas");
|
|
GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, sourceUUIDInCall, -1);
|
|
}
|
|
};
|
|
|
|
openers.push_back({ "O3DE_ScriptCanvasEditor", "Open In Script Canvas Editor...", QIcon(), scriptCanvasEditorCallback });
|
|
}
|
|
}
|
|
|
|
void SystemComponent::OnUserSettingsActivated()
|
|
{
|
|
PopulateEditorCreatableTypes();
|
|
}
|
|
|
|
void SystemComponent::PopulateEditorCreatableTypes()
|
|
{
|
|
AZ::BehaviorContext* behaviorContext{};
|
|
AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationRequests::GetBehaviorContext);
|
|
AZ_Assert(behaviorContext, "Behavior Context should not be missing at this point");
|
|
|
|
auto dataRegistry = ScriptCanvas::GetDataRegistry();
|
|
for (const auto& scType : dataRegistry->m_creatableTypes)
|
|
{
|
|
if (scType.first.GetType() == ScriptCanvas::Data::eType::BehaviorContextObject)
|
|
{
|
|
if (const AZ::BehaviorClass* behaviorClass = AZ::BehaviorContextHelper::GetClass(behaviorContext, ScriptCanvas::Data::ToAZType(scType.first)))
|
|
{
|
|
// BehaviorContext classes with the ExcludeFrom attribute with a value of the ExcludeFlags::All are not added to the list of
|
|
// types that can be created in the editor
|
|
const AZ::u64 exclusionFlags = AZ::Script::Attributes::ExcludeFlags::All;
|
|
auto excludeClassAttributeData = azrtti_cast<const AZ::Edit::AttributeData<AZ::Script::Attributes::ExcludeFlags>*>(AZ::FindAttribute(AZ::Script::Attributes::ExcludeFrom, behaviorClass->m_attributes));
|
|
if (excludeClassAttributeData && (excludeClassAttributeData->Get(nullptr) & exclusionFlags))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_creatableTypes.insert(scType.first);
|
|
}
|
|
}
|
|
|
|
Reporter SystemComponent::RunGraph(AZStd::string_view path, ScriptCanvas::ExecutionMode mode)
|
|
{
|
|
RunGraphSpec runGraphSpec;
|
|
runGraphSpec.graphPath = path;
|
|
runGraphSpec.runSpec.execution = mode;
|
|
return ScriptCanvasEditor::RunGraph(runGraphSpec).front();
|
|
}
|
|
|
|
Reporter SystemComponent::RunAssetGraph(AZ::Data::Asset<AZ::Data::AssetData> asset, ScriptCanvas::ExecutionMode mode)
|
|
{
|
|
Reporter reporter;
|
|
RunEditorAsset(asset, reporter, mode);
|
|
return reporter;
|
|
}
|
|
|
|
void SystemComponent::OnCatalogLoaded(const char* /*catalogFile*/)
|
|
{
|
|
// Enumerate all ScriptCanvas assets
|
|
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<ScriptCanvasAsset>() || assetInfo.m_assetType == azrtti_typeid<ScriptCanvasFunctionAsset>())
|
|
{
|
|
AddAssetToUpgrade(assetInfo);
|
|
}
|
|
},
|
|
nullptr
|
|
);
|
|
}
|
|
|
|
void SystemComponent::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId)
|
|
{
|
|
if (IsUpgrading())
|
|
{
|
|
return;
|
|
}
|
|
|
|
auto assetInfo = ScriptCanvasEditor::AssetHelpers::GetAssetInfo(assetId);
|
|
AddAssetToUpgrade(assetInfo);
|
|
}
|
|
|
|
void SystemComponent::OnCatalogAssetRemoved(const AZ::Data::AssetId& assetId, const AZ::Data::AssetInfo& /*assetInfo*/)
|
|
{
|
|
if (IsUpgrading())
|
|
{
|
|
return;
|
|
}
|
|
|
|
AZStd::erase_if(m_assetsToConvert, [assetId](const AZ::Data::AssetInfo& assetToConvert)
|
|
{
|
|
return assetToConvert.m_assetId == assetId;
|
|
}
|
|
);
|
|
}
|
|
|
|
void SystemComponent::AddAssetToUpgrade(const AZ::Data::AssetInfo& assetInfo)
|
|
{
|
|
auto query = AZStd::find_if(m_assetsToConvert.begin(), m_assetsToConvert.end(), [assetInfo](const AZ::Data::AssetInfo& assetToConvert)
|
|
{
|
|
return assetToConvert.m_assetId == assetInfo.m_assetId;
|
|
}
|
|
);
|
|
|
|
if (query == m_assetsToConvert.end())
|
|
{
|
|
if (assetInfo.m_assetType == azrtti_typeid<ScriptCanvasFunctionAsset>())
|
|
{
|
|
m_assetsToConvert.push_front(assetInfo);
|
|
}
|
|
else if (assetInfo.m_assetType == azrtti_typeid<ScriptCanvasAsset>())
|
|
{
|
|
m_assetsToConvert.push_back(assetInfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
AzToolsFramework::AssetSeedManagerRequests::AssetTypePairs SystemComponent::GetAssetTypeMapping()
|
|
{
|
|
return {
|
|
{ "scriptcanvas", "scriptcanvas_compiled" },
|
|
{ "scriptcanvas_fn", "scriptcanvas_fn_compiled" }
|
|
};
|
|
}
|
|
|
|
}
|