3
0

SystemComponent.cpp 17 KB

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