SystemComponent.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/EBus/Results.h>
  9. #include <AzCore/Jobs/JobFunction.h>
  10. #include <AzCore/Serialization/EditContext.h>
  11. #include <AzCore/Serialization/SerializeContext.h>
  12. #include <AzCore/Serialization/Utils.h>
  13. #include <AzCore/StringFunc/StringFunc.h>
  14. #include <AzCore/std/string/wildcard.h>
  15. #include <AzFramework/Entity/EntityContextBus.h>
  16. #include <AzFramework/Network/IRemoteTools.h>
  17. #include <AzFramework/IO/FileOperations.h>
  18. #include <AzToolsFramework/ActionManager/Action/ActionManagerInterface.h>
  19. #include <AzToolsFramework/API/ViewPaneOptions.h>
  20. #include <AzToolsFramework/AssetBrowser/Entries/SourceAssetBrowserEntry.h>
  21. #include <AzToolsFramework/UI/PropertyEditor/GenericComboBoxCtrl.h>
  22. #include <Editor/Assets/ScriptCanvasAssetHelpers.h>
  23. #include <Editor/Framework/ScriptCanvasGraphUtilities.h>
  24. #include <Editor/Settings.h>
  25. #include <Editor/SystemComponent.h>
  26. #include <Editor/View/Dialogs/SettingsDialog.h>
  27. #include <Editor/View/Widgets/SourceHandlePropertyAssetCtrl.h>
  28. #include <Editor/View/Windows/MainWindow.h>
  29. #include <GraphCanvas/GraphCanvasBus.h>
  30. #include <LyViewPaneNames.h>
  31. #include <QFileInfo>
  32. #include <QDir>
  33. #include <QMenu>
  34. #include <ScriptCanvasContextIdentifiers.h>
  35. #include <ScriptCanvas/Bus/EditorScriptCanvasBus.h>
  36. #include <ScriptCanvas/Components/EditorGraph.h>
  37. #include <ScriptCanvas/Components/EditorGraphVariableManagerComponent.h>
  38. #include <ScriptCanvas/Core/Datum.h>
  39. #include <ScriptCanvas/Data/DataRegistry.h>
  40. #include <ScriptCanvas/Libraries/Libraries.h>
  41. #include <ScriptCanvas/PerformanceStatisticsBus.h>
  42. #include <ScriptCanvas/Utils/ScriptCanvasConstants.h>
  43. #include <ScriptCanvas/Variable/VariableCore.h>
  44. namespace ScriptCanvasEditor
  45. {
  46. static const size_t cs_jobThreads = 1;
  47. SystemComponent::SystemComponent()
  48. {
  49. AzToolsFramework::AssetSeedManagerRequests::Bus::Handler::BusConnect();
  50. AZ::SystemTickBus::Handler::BusConnect();
  51. m_versionExplorer = AZStd::make_unique<VersionExplorer::Model>();
  52. }
  53. SystemComponent::~SystemComponent()
  54. {
  55. AzToolsFramework::UnregisterViewPane(LyViewPane::ScriptCanvas);
  56. AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect();
  57. AzToolsFramework::AssetSeedManagerRequests::Bus::Handler::BusDisconnect();
  58. AZ::SystemTickBus::Handler::BusDisconnect();
  59. }
  60. void SystemComponent::Reflect(AZ::ReflectContext* context)
  61. {
  62. if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
  63. {
  64. ScriptCanvasEditor::Settings::Reflect(serialize);
  65. serialize->Class<SystemComponent, AZ::Component>()
  66. ->Version(0)
  67. ;
  68. if (AZ::EditContext* ec = serialize->GetEditContext())
  69. {
  70. ec->Class<SystemComponent>("Script Canvas Editor", "Script Canvas Editor System Component")
  71. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  72. ->Attribute(AZ::Edit::Attributes::Category, "Scripting")
  73. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  74. ;
  75. }
  76. }
  77. }
  78. void SystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  79. {
  80. provided.push_back(AZ_CRC_CE("ScriptCanvasEditorService"));
  81. }
  82. void SystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  83. {
  84. (void)incompatible;
  85. }
  86. void SystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  87. {
  88. required.push_back(AZ_CRC_CE("ScriptCanvasService"));
  89. required.push_back(GraphCanvas::GraphCanvasRequestsServiceId);
  90. required.push_back(AZ_CRC_CE("ScriptCanvasReflectService"));
  91. }
  92. void SystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
  93. {
  94. (void)dependent;
  95. }
  96. void SystemComponent::Init()
  97. {
  98. AzToolsFramework::EditorEvents::Bus::Handler::BusConnect();
  99. }
  100. void SystemComponent::Activate()
  101. {
  102. #if defined(ENABLE_REMOTE_TOOLS)
  103. if (auto* remoteToolsInterface = AzFramework::RemoteToolsInterface::Get())
  104. {
  105. remoteToolsInterface->RegisterToolingServiceHost(
  106. ScriptCanvas::RemoteToolsKey, ScriptCanvas::RemoteToolsName, ScriptCanvas::RemoteToolsPort);
  107. }
  108. #endif
  109. AZ::JobManagerDesc jobDesc;
  110. for (size_t i = 0; i < cs_jobThreads; ++i)
  111. {
  112. jobDesc.m_workerThreads.push_back({ static_cast<int>(i) });
  113. }
  114. m_jobManager = AZStd::make_unique<AZ::JobManager>(jobDesc);
  115. m_jobContext = AZStd::make_unique<AZ::JobContext>(*m_jobManager);
  116. PopulateEditorCreatableTypes();
  117. AzToolsFramework::RegisterGenericComboBoxHandler<ScriptCanvas::VariableId>();
  118. if (AzToolsFramework::PropertyTypeRegistrationMessages::Bus::FindFirstHandler())
  119. {
  120. AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Broadcast(&AzToolsFramework::PropertyTypeRegistrationMessages::RegisterPropertyType, aznew SourceHandlePropertyHandler());
  121. }
  122. SystemRequestBus::Handler::BusConnect();
  123. ScriptCanvasExecutionBus::Handler::BusConnect();
  124. AzToolsFramework::EditorEvents::Bus::Handler::BusConnect();
  125. AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect();
  126. AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusConnect();
  127. AzToolsFramework::ActionManagerRegistrationNotificationBus::Handler::BusConnect();
  128. auto userSettings = AZ::UserSettings::CreateFind<EditorSettings::ScriptCanvasEditorSettings>(AZ_CRC_CE("ScriptCanvasPreviewSettings"), AZ::UserSettings::CT_LOCAL);
  129. if (userSettings)
  130. {
  131. if (userSettings->m_showUpgradeDialog)
  132. {
  133. }
  134. else
  135. {
  136. m_upgradeDisabled = true;
  137. }
  138. }
  139. m_nodeReplacementSystem.LoadReplacementMetadata();
  140. }
  141. void SystemComponent::NotifyRegisterViews()
  142. {
  143. QtViewOptions options;
  144. options.canHaveMultipleInstances = false;
  145. options.isPreview = true;
  146. options.showInMenu = true;
  147. options.showOnToolsToolbar = true;
  148. options.toolbarIcon = ":/Menu/script_canvas_editor.svg";
  149. AzToolsFramework::RegisterViewPane<ScriptCanvasEditor::MainWindow>(LyViewPane::ScriptCanvas, LyViewPane::CategoryTools, options);
  150. }
  151. void SystemComponent::Deactivate()
  152. {
  153. AzToolsFramework::ActionManagerRegistrationNotificationBus::Handler::BusDisconnect();
  154. m_nodeReplacementSystem.UnloadReplacementMetadata();
  155. AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusDisconnect();
  156. AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect();
  157. ScriptCanvasExecutionBus::Handler::BusDisconnect();
  158. SystemRequestBus::Handler::BusDisconnect();
  159. AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusDisconnect();
  160. m_jobContext.reset();
  161. m_jobManager.reset();
  162. }
  163. void SystemComponent::CreateEditorComponentsOnEntity(AZ::Entity* entity, [[maybe_unused]] const AZ::Data::AssetType& assetType)
  164. {
  165. if (entity)
  166. {
  167. auto graph = entity->CreateComponent<EditorGraph>();
  168. entity->CreateComponent<EditorGraphVariableManagerComponent>(graph->GetScriptCanvasId());
  169. }
  170. }
  171. void SystemComponent::GetEditorCreatableTypes(AZStd::unordered_set<ScriptCanvas::Data::Type>& outCreatableTypes)
  172. {
  173. outCreatableTypes.insert(m_creatableTypes.begin(), m_creatableTypes.end());
  174. }
  175. void SystemComponent::RequestGarbageCollect()
  176. {
  177. m_isGarbageCollectRequested = true;
  178. }
  179. AzToolsFramework::AssetBrowser::SourceFileDetails SystemComponent::GetSourceFileDetails(const char* fullSourceFileName)
  180. {
  181. if (AZStd::wildcard_match("*.scriptcanvas", fullSourceFileName))
  182. {
  183. return AzToolsFramework::AssetBrowser::SourceFileDetails("../Editor/Icons/AssetBrowser/ScriptCanvas_80.svg");
  184. }
  185. // not one of our types.
  186. return AzToolsFramework::AssetBrowser::SourceFileDetails();
  187. }
  188. void SystemComponent::AddSourceFileCreators
  189. ( [[maybe_unused]] const char* fullSourceFolderName
  190. , [[maybe_unused]] const AZ::Uuid& sourceUUID
  191. , AzToolsFramework::AssetBrowser::SourceFileCreatorList& creators)
  192. {
  193. auto scriptCavnasAssetCreator = [](const AZStd::string& fullSourceFolderNameInCallback, [[maybe_unused]] const AZ::Uuid& sourceUUID)
  194. {
  195. const AZStd::string defaultFilename = "NewScript";
  196. const AZStd::string scriptCanvasExtension = ScriptCanvasEditor::SourceDescription::GetFileExtension();
  197. AZStd::string fullFilepath;
  198. AZ::StringFunc::Path::ConstructFull(fullSourceFolderNameInCallback.c_str()
  199. , defaultFilename.c_str()
  200. , scriptCanvasExtension.c_str()
  201. , fullFilepath);
  202. int fileCounter = 0;
  203. while (AZ::IO::FileIOBase::GetInstance()->Exists(fullFilepath.c_str()))
  204. {
  205. fileCounter++;
  206. const AZStd::string incrementalFilename = defaultFilename + AZStd::to_string(fileCounter);
  207. AZ::StringFunc::Path::ConstructFull(fullSourceFolderNameInCallback.c_str()
  208. , incrementalFilename.c_str()
  209. , scriptCanvasExtension.c_str()
  210. , fullFilepath);
  211. }
  212. const AZ::IO::Path fullAzFilePath = fullFilepath;
  213. const ScriptCanvas::DataPtr graph = EditorGraph::Create();
  214. SourceHandle source = SourceHandle::FromRelativePath(graph, fullAzFilePath.RelativePath());
  215. source = SourceHandle::MarkAbsolutePath(source, fullAzFilePath);
  216. AZ::IO::FileIOStream fileStream(fullAzFilePath.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText);
  217. if (fileStream.IsOpen())
  218. {
  219. auto serializeResult = Serialize(*source.Data(), fileStream);
  220. if (!serializeResult)
  221. {
  222. AZ_Error("ScriptCanvasCreator", false, "Failed to save new ScriptCanvas file: %s", serializeResult.m_errors.c_str());
  223. }
  224. else
  225. {
  226. AzToolsFramework::AssetBrowser::AssetBrowserFileCreationNotificationBus::Event(
  227. AzToolsFramework::AssetBrowser::AssetBrowserFileCreationNotifications::FileCreationNotificationBusId,
  228. &AzToolsFramework::AssetBrowser::AssetBrowserFileCreationNotifications::HandleAssetCreatedInEditor,
  229. source.AbsolutePath().Native(),
  230. AZ::Crc32(),
  231. true);
  232. }
  233. fileStream.Close();
  234. }
  235. else
  236. {
  237. AZ_Error("ScriptCanvasCreator", false, "Asset creation failed because file failed to open: %s", fullAzFilePath.c_str());
  238. }
  239. };
  240. creators.push_back({ "ScriptCanvas_creator", "ScriptCanvas Graph", QIcon(), scriptCavnasAssetCreator });
  241. }
  242. void SystemComponent::AddSourceFileOpeners
  243. ( [[maybe_unused]] const char* fullSourceFileName
  244. , [[maybe_unused]] const AZ::Uuid& sourceUUID
  245. , [[maybe_unused]] AzToolsFramework::AssetBrowser::SourceFileOpenerList& openers)
  246. {
  247. using namespace AzToolsFramework;
  248. using namespace AzToolsFramework::AssetBrowser;
  249. if (AZ::IO::Path(fullSourceFileName).Extension() == ScriptCanvasEditor::SourceDescription::GetFileExtension())
  250. {
  251. auto scriptCanvasOpenInEditorCallback = []([[maybe_unused]] const char* fullSourceFileNameInCall, const AZ::Uuid& sourceUUIDInCall)
  252. {
  253. AZ::Outcome<int, AZStd::string> openOutcome = AZ::Failure(AZStd::string());
  254. auto sourceHandle = CompleteDescription(SourceHandle(nullptr, sourceUUIDInCall));
  255. if (sourceHandle)
  256. {
  257. AzToolsFramework::EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::OpenViewPane, "Script Canvas");
  258. GeneralRequestBus::BroadcastResult(openOutcome
  259. , &GeneralRequests::OpenScriptCanvasAsset
  260. , *sourceHandle
  261. , Tracker::ScriptCanvasFileState::UNMODIFIED
  262. , -1);
  263. if (!openOutcome.IsSuccess())
  264. {
  265. AZ_Error("ScriptCanvas", false, openOutcome.GetError().data());
  266. }
  267. }
  268. else
  269. {
  270. AZ_Warning("ScriptCanvas", false
  271. , "Unabled to find full path for Source UUid %s", sourceUUIDInCall.ToString<AZStd::string>().c_str());
  272. }
  273. };
  274. openers.push_back({ "O3DE_ScriptCanvasEditor"
  275. , "Open In Script Canvas Editor..."
  276. , QIcon(ScriptCanvasEditor::SourceDescription::GetIconPath())
  277. , scriptCanvasOpenInEditorCallback });
  278. }
  279. }
  280. void SystemComponent::OnStartPlayInEditor()
  281. {
  282. ScriptCanvas::Execution::PerformanceStatisticsEBus::Broadcast(&ScriptCanvas::Execution::PerformanceStatisticsBus::ClearSnaphotStatistics);
  283. }
  284. void SystemComponent::OnStopPlayInEditor()
  285. {
  286. AZ::ScriptSystemRequestBus::Broadcast(&AZ::ScriptSystemRequests::GarbageCollect);
  287. }
  288. void SystemComponent::OnSystemTick()
  289. {
  290. if (m_isGarbageCollectRequested)
  291. {
  292. m_isGarbageCollectRequested = false;
  293. AZ::ScriptSystemRequestBus::Broadcast(&AZ::ScriptSystemRequests::GarbageCollect);
  294. }
  295. }
  296. void SystemComponent::OnUserSettingsActivated()
  297. {
  298. PopulateEditorCreatableTypes();
  299. }
  300. void SystemComponent::PopulateEditorCreatableTypes()
  301. {
  302. AZ::BehaviorContext* behaviorContext{};
  303. AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationRequests::GetBehaviorContext);
  304. AZ_Assert(behaviorContext, "Behavior Context should not be missing at this point");
  305. auto dataRegistry = ScriptCanvas::GetDataRegistry();
  306. for (const auto& scType : dataRegistry->m_creatableTypes)
  307. {
  308. if (scType.first.GetType() == ScriptCanvas::Data::eType::BehaviorContextObject)
  309. {
  310. if (const AZ::BehaviorClass* behaviorClass = AZ::BehaviorContextHelper::GetClass(behaviorContext, ScriptCanvas::Data::ToAZType(scType.first)))
  311. {
  312. // BehaviorContext classes with the ExcludeFrom attribute with a value of the ExcludeFlags::All are not added to the list of
  313. // types that can be created in the editor
  314. const AZ::u64 exclusionFlags = AZ::Script::Attributes::ExcludeFlags::All;
  315. auto excludeClassAttributeData = azrtti_cast<const AZ::Edit::AttributeData<AZ::Script::Attributes::ExcludeFlags>*>(AZ::FindAttribute(AZ::Script::Attributes::ExcludeFrom, behaviorClass->m_attributes));
  316. if (excludeClassAttributeData && (excludeClassAttributeData->Get(nullptr) & exclusionFlags))
  317. {
  318. continue;
  319. }
  320. }
  321. }
  322. m_creatableTypes.insert(scType.first);
  323. }
  324. }
  325. Reporter SystemComponent::RunAssetGraph(SourceHandle asset, ScriptCanvas::ExecutionMode mode)
  326. {
  327. Reporter reporter;
  328. RunEditorAsset(asset, reporter, mode);
  329. return reporter;
  330. }
  331. Reporter SystemComponent::RunGraph(AZStd::string_view path, ScriptCanvas::ExecutionMode mode)
  332. {
  333. RunGraphSpec runGraphSpec;
  334. runGraphSpec.graphPath = path;
  335. runGraphSpec.runSpec.execution = mode;
  336. return ScriptCanvasEditor::RunGraph(runGraphSpec).front();
  337. }
  338. AzToolsFramework::AssetSeedManagerRequests::AssetTypePairs SystemComponent::GetAssetTypeMapping()
  339. {
  340. return {
  341. { "scriptcanvas", "scriptcanvas_compiled" },
  342. { "scriptcanvas_fn", "scriptcanvas_fn_compiled" }
  343. };
  344. }
  345. void SystemComponent::OnActionContextRegistrationHook()
  346. {
  347. if (auto actionManagerInterface = AZ::Interface<AzToolsFramework::ActionManagerInterface>::Get())
  348. {
  349. AzToolsFramework::ActionContextProperties contextProperties;
  350. contextProperties.m_name = "O3DE Script Canvas";
  351. // Register custom action contexts to allow duplicated shortcut hotkeys to work
  352. actionManagerInterface->RegisterActionContext(ScriptCanvasIdentifiers::ScriptCanvasActionContextIdentifier, contextProperties);
  353. actionManagerInterface->RegisterActionContext(ScriptCanvasIdentifiers::ScriptCanvasVariablesActionContextIdentifier, contextProperties);
  354. }
  355. }
  356. }