EditorScriptCanvasComponent.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project
  3. *
  4. * SPDX-License-Identifier: Apache-2.0 OR MIT
  5. *
  6. */
  7. #include "precompiled.h"
  8. #include <AzCore/Asset/AssetManagerBus.h>
  9. #include <AzCore/Component/ComponentApplicationBus.h>
  10. #include <AzCore/Component/NamedEntityId.h>
  11. #include <AzCore/IO/FileIO.h>
  12. #include <AzCore/Script/ScriptSystemBus.h>
  13. #include <AzCore/Serialization/EditContext.h>
  14. #include <AzCore/Serialization/IdUtils.h>
  15. #include <AzCore/Serialization/Utils.h>
  16. #include <AzFramework/Asset/AssetSystemBus.h>
  17. #include <AzFramework/StringFunc/StringFunc.h>
  18. #include <AzToolsFramework/API/EditorAssetSystemAPI.h>
  19. #include <AzToolsFramework/API/ToolsApplicationAPI.h>
  20. #include <Core/ScriptCanvasBus.h>
  21. #include <Editor/Assets/ScriptCanvasAssetTrackerBus.h>
  22. #include <ScriptCanvas/Asset/RuntimeAsset.h>
  23. #include <ScriptCanvas/Assets/ScriptCanvasAsset.h>
  24. #include <ScriptCanvas/Bus/RequestBus.h>
  25. #include <ScriptCanvas/Components/EditorGraph.h>
  26. #include <ScriptCanvas/Components/EditorGraphVariableManagerComponent.h>
  27. #include <ScriptCanvas/Components/EditorScriptCanvasComponent.h>
  28. #include <ScriptCanvas/Core/Node.h>
  29. #include <ScriptCanvas/Execution/RuntimeComponent.h>
  30. #include <ScriptCanvas/PerformanceStatisticsBus.h>
  31. namespace ScriptCanvasEditor
  32. {
  33. static bool EditorScriptCanvasComponentVersionConverter(AZ::SerializeContext& serializeContext, AZ::SerializeContext::DataElementNode& rootElement)
  34. {
  35. if (rootElement.GetVersion() <= 4)
  36. {
  37. int assetElementIndex = rootElement.FindElement(AZ::Crc32("m_asset"));
  38. if (assetElementIndex == -1)
  39. {
  40. return false;
  41. }
  42. auto assetElement = rootElement.GetSubElement(assetElementIndex);
  43. AZ::Data::Asset<ScriptCanvasAsset> scriptCanvasAsset;
  44. if (!assetElement.GetData(scriptCanvasAsset))
  45. {
  46. AZ_Error("Script Canvas", false, "Unable to find Script Canvas Asset on a Version %u Editor ScriptCanvas Component", rootElement.GetVersion());
  47. return false;
  48. }
  49. ScriptCanvasAssetHolder assetHolder;
  50. assetHolder.SetAsset(scriptCanvasAsset.GetId());
  51. if (!rootElement.AddElementWithData(serializeContext, "m_assetHolder", assetHolder))
  52. {
  53. AZ_Error("Script Canvas", false, "Unable to add ScriptCanvas Asset Holder element when converting from version %u", rootElement.GetVersion())
  54. }
  55. rootElement.RemoveElementByName(AZ_CRC("m_asset", 0x4e58e538));
  56. rootElement.RemoveElementByName(AZ_CRC("m_openEditorButton", 0x9bcb3d5b));
  57. }
  58. if (rootElement.GetVersion() <= 6)
  59. {
  60. rootElement.RemoveElementByName(AZ_CRC("m_originalData", 0x2aee5989));
  61. }
  62. if (rootElement.GetVersion() <= 7)
  63. {
  64. rootElement.RemoveElementByName(AZ_CRC("m_variableEntityIdMap", 0xdc6c75a8));
  65. }
  66. return true;
  67. }
  68. //=========================================================================
  69. void EditorScriptCanvasComponent::Reflect(AZ::ReflectContext* context)
  70. {
  71. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  72. {
  73. serializeContext->Class<EditorScriptCanvasComponent, EditorComponentBase>()
  74. ->Version(8, &EditorScriptCanvasComponentVersionConverter)
  75. ->Field("m_name", &EditorScriptCanvasComponent::m_name)
  76. ->Field("m_assetHolder", &EditorScriptCanvasComponent::m_scriptCanvasAssetHolder)
  77. ->Field("m_variableData", &EditorScriptCanvasComponent::m_editableData)
  78. ;
  79. if (AZ::EditContext* editContext = serializeContext->GetEditContext())
  80. {
  81. editContext->Class<EditorScriptCanvasComponent>("Script Canvas", "The Script Canvas component allows you to add a Script Canvas asset to a component, and have it execute on the specified entity.")
  82. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  83. ->Attribute(AZ::Edit::Attributes::Category, "Scripting")
  84. ->Attribute(AZ::Edit::Attributes::Icon, "Icons/ScriptCanvas/ScriptCanvas.svg")
  85. ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/ScriptCanvas/Viewport/ScriptCanvas.png")
  86. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  87. ->Attribute(AZ::Edit::Attributes::PrimaryAssetType, ScriptCanvasAssetHandler::GetAssetTypeStatic())
  88. ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
  89. ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("UI", 0x27ff46b0))
  90. ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Level", 0x9aeacc13))
  91. ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/script-canvas/")
  92. ->DataElement(AZ::Edit::UIHandlers::Default, &EditorScriptCanvasComponent::m_scriptCanvasAssetHolder, "Script Canvas Asset", "Script Canvas asset associated with this component")
  93. ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
  94. ->DataElement(AZ::Edit::UIHandlers::Default, &EditorScriptCanvasComponent::m_editableData, "Properties", "Script Canvas Graph Properties")
  95. ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
  96. ;
  97. }
  98. }
  99. }
  100. EditorScriptCanvasComponent::EditorScriptCanvasComponent()
  101. : EditorScriptCanvasComponent(AZ::Data::Asset<ScriptCanvasAsset>())
  102. {
  103. }
  104. EditorScriptCanvasComponent::EditorScriptCanvasComponent(AZ::Data::Asset<ScriptCanvasAsset> asset)
  105. : m_scriptCanvasAssetHolder()
  106. {
  107. if (asset.GetId().IsValid())
  108. {
  109. m_scriptCanvasAssetHolder.SetAsset(asset.GetId());
  110. }
  111. m_scriptCanvasAssetHolder.SetScriptChangedCB([this](AZ::Data::AssetId assetId) { OnScriptCanvasAssetChanged(assetId); });
  112. }
  113. EditorScriptCanvasComponent::~EditorScriptCanvasComponent()
  114. {
  115. AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusDisconnect();
  116. AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
  117. }
  118. void EditorScriptCanvasComponent::UpdateName()
  119. {
  120. AZ::Data::AssetId assetId = m_scriptCanvasAssetHolder.GetAssetId();
  121. if (assetId.IsValid())
  122. {
  123. // 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).
  124. // Using the Job system to determine the asset name instead.
  125. AZ::Outcome<AzToolsFramework::AssetSystem::JobInfoContainer> jobOutcome = AZ::Failure();
  126. AzToolsFramework::AssetSystemJobRequestBus::BroadcastResult(jobOutcome, &AzToolsFramework::AssetSystemJobRequestBus::Events::GetAssetJobsInfoByAssetID, assetId, false, false);
  127. AZStd::string assetPath;
  128. AZStd::string assetName;
  129. if (jobOutcome.IsSuccess())
  130. {
  131. AzToolsFramework::AssetSystem::JobInfoContainer& jobs = jobOutcome.GetValue();
  132. // Get the asset relative path
  133. if (!jobs.empty())
  134. {
  135. assetPath = jobs[0].m_sourceFile;
  136. }
  137. // Get the asset file name
  138. assetName = assetPath;
  139. if (!assetPath.empty())
  140. {
  141. AzFramework::StringFunc::Path::GetFileName(assetPath.c_str(), assetName);
  142. SetName(assetName);
  143. }
  144. }
  145. }
  146. }
  147. void EditorScriptCanvasComponent::OpenEditor()
  148. {
  149. m_scriptCanvasAssetHolder.OpenEditor();
  150. }
  151. void EditorScriptCanvasComponent::CloseGraph()
  152. {
  153. AZ::Data::AssetId assetId = m_scriptCanvasAssetHolder.GetAssetId();
  154. if (assetId.IsValid())
  155. {
  156. GeneralRequestBus::Broadcast(&GeneralRequests::CloseScriptCanvasAsset, assetId);
  157. }
  158. }
  159. void EditorScriptCanvasComponent::Init()
  160. {
  161. EditorComponentBase::Init();
  162. AzFramework::AssetCatalogEventBus::Handler::BusConnect();
  163. AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusConnect();
  164. m_scriptCanvasAssetHolder.Init(GetEntityId(), GetId());
  165. }
  166. //=========================================================================
  167. void EditorScriptCanvasComponent::Activate()
  168. {
  169. EditorComponentBase::Activate();
  170. AZ::EntityId entityId = GetEntityId();
  171. EditorContextMenuRequestBus::Handler::BusConnect(entityId);
  172. EditorScriptCanvasComponentRequestBus::Handler::BusConnect(entityId);
  173. EditorScriptCanvasComponentLoggingBus::Handler::BusConnect(entityId);
  174. EditorLoggingComponentNotificationBus::Broadcast(&EditorLoggingComponentNotifications::OnEditorScriptCanvasComponentActivated, GetNamedEntityId(), GetGraphIdentifier());
  175. AZ::Data::AssetId fileAssetId = m_scriptCanvasAssetHolder.GetAssetId();
  176. if (fileAssetId.IsValid())
  177. {
  178. AssetTrackerNotificationBus::Handler::BusConnect(fileAssetId);
  179. ScriptCanvasMemoryAsset::pointer memoryAsset;
  180. AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, fileAssetId);
  181. if (memoryAsset && memoryAsset->GetAsset().GetStatus() == AZ::Data::AssetData::AssetStatus::Ready)
  182. {
  183. OnScriptCanvasAssetReady(memoryAsset);
  184. }
  185. else
  186. {
  187. AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::Load, m_scriptCanvasAssetHolder.GetAssetId(), m_scriptCanvasAssetHolder.GetAssetType(), nullptr);
  188. }
  189. }
  190. }
  191. //=========================================================================
  192. void EditorScriptCanvasComponent::Deactivate()
  193. {
  194. AssetTrackerNotificationBus::Handler::BusDisconnect();
  195. EditorScriptCanvasComponentLoggingBus::Handler::BusDisconnect();
  196. EditorLoggingComponentNotificationBus::Broadcast(&EditorLoggingComponentNotifications::OnEditorScriptCanvasComponentDeactivated, GetNamedEntityId(), GetGraphIdentifier());
  197. EditorComponentBase::Deactivate();
  198. //EditorScriptCanvasAssetNotificationBus::Handler::BusDisconnect();
  199. EditorScriptCanvasComponentRequestBus::Handler::BusDisconnect();
  200. EditorContextMenuRequestBus::Handler::BusDisconnect();
  201. }
  202. //=========================================================================
  203. void EditorScriptCanvasComponent::BuildGameEntity(AZ::Entity* gameEntity)
  204. {
  205. AZ::Data::AssetId editorAssetId = m_scriptCanvasAssetHolder.GetAssetId();
  206. if (!editorAssetId.IsValid())
  207. {
  208. return;
  209. }
  210. AZ::Data::AssetId runtimeAssetId(editorAssetId.m_guid, AZ_CRC("RuntimeData", 0x163310ae));
  211. AZ::Data::Asset<ScriptCanvas::RuntimeAsset> runtimeAsset(runtimeAssetId, azrtti_typeid<ScriptCanvas::RuntimeAsset>(), {});
  212. /*
  213. This defense against creating useless runtime components is pending changes the slice update system.
  214. It also would require better abilities to check asset integrity when building assets that depend
  215. on ScriptCanvas assets.
  216. AZ::Data::AssetInfo assetInfo;
  217. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, runtimeAssetId);
  218. if (assetInfo.m_assetType == AZ::Data::s_invalidAssetType)
  219. {
  220. AZ_Warning("ScriptCanvas", false, "No ScriptCanvas Runtime Asset information for Entity ('%s' - '%s') Graph ('%s'), asset may be in error or deleted"
  221. , gameEntity->GetName().c_str()
  222. , GetEntityId().ToString().c_str()
  223. , GetName().c_str());
  224. return;
  225. }
  226. AzFramework::AssetSystem::AssetStatus statusResult = AzFramework::AssetSystem::AssetStatus_Unknown;
  227. AzFramework::AssetSystemRequestBus::BroadcastResult(statusResult, &AzFramework::AssetSystem::AssetSystemRequests::GetAssetStatusById, runtimeAssetId);
  228. if (statusResult != AzFramework::AssetSystem::AssetStatus_Compiled)
  229. {
  230. AZ_Warning("ScriptCanvas", false, "No ScriptCanvas Runtime Asset for Entity ('%s' - '%s') Graph ('%s'), compilation may have failed or not completed"
  231. , gameEntity->GetName().c_str()
  232. , GetEntityId().ToString().c_str()
  233. , GetName().c_str());
  234. return;
  235. }
  236. */
  237. // #functions2 dependency-ctor-args make recursive
  238. auto executionComponent = gameEntity->CreateComponent<ScriptCanvas::RuntimeComponent>(runtimeAsset);
  239. ScriptCanvas::VariableData varData;
  240. for (const auto& varConfig : m_editableData.GetVariables())
  241. {
  242. if (varConfig.m_graphVariable.GetDatum()->Empty())
  243. {
  244. AZ_Error("ScriptCanvas", false, "Data loss detected for GraphVariable ('%s') on Entity ('%s' - '%s') Graph ('%s')"
  245. , varConfig.m_graphVariable.GetVariableName().data()
  246. , gameEntity->GetName().c_str()
  247. , GetEntityId().ToString().c_str()
  248. , GetName().c_str());
  249. }
  250. else
  251. {
  252. varData.AddVariable(varConfig.m_graphVariable.GetVariableName(), varConfig.m_graphVariable);
  253. }
  254. }
  255. executionComponent->SetVariableOverrides(varData);
  256. }
  257. void EditorScriptCanvasComponent::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId)
  258. {
  259. // If we removed out asset due to the catalog removing. Just set it back.
  260. if (m_removedCatalogId == assetId)
  261. {
  262. if (!m_scriptCanvasAssetHolder.GetAssetId().IsValid())
  263. {
  264. SetPrimaryAsset(assetId);
  265. m_removedCatalogId.SetInvalid();
  266. }
  267. }
  268. }
  269. void EditorScriptCanvasComponent::OnCatalogAssetRemoved(const AZ::Data::AssetId& removedAssetId, const AZ::Data::AssetInfo& /*assetInfo*/)
  270. {
  271. AZ::Data::AssetId assetId = m_scriptCanvasAssetHolder.GetAssetId();
  272. // If the Asset gets removed from disk while the Editor is loaded clear out the asset reference.
  273. if (assetId == removedAssetId)
  274. {
  275. m_removedCatalogId = assetId;
  276. SetPrimaryAsset({});
  277. }
  278. }
  279. void EditorScriptCanvasComponent::SetPrimaryAsset(const AZ::Data::AssetId& assetId)
  280. {
  281. m_scriptCanvasAssetHolder.ClearAsset();
  282. if (assetId.IsValid())
  283. {
  284. ScriptCanvasMemoryAsset::pointer memoryAsset;
  285. AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId);
  286. if (memoryAsset)
  287. {
  288. m_scriptCanvasAssetHolder.SetAsset(memoryAsset->GetFileAssetId());
  289. OnScriptCanvasAssetChanged(memoryAsset->GetFileAssetId());
  290. SetName(memoryAsset->GetTabName());
  291. }
  292. else
  293. {
  294. auto scriptCanvasAsset = AZ::Data::AssetManager::Instance().FindAsset(assetId, AZ::Data::AssetLoadBehavior::Default);
  295. if (scriptCanvasAsset)
  296. {
  297. m_scriptCanvasAssetHolder.SetAsset(assetId);
  298. }
  299. }
  300. }
  301. AzToolsFramework::ScopedUndoBatch undo("Update Entity With New SC Graph");
  302. AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast(&AzToolsFramework::ToolsApplicationRequests::Bus::Events::AddDirtyEntity, GetEntityId());
  303. AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues);
  304. }
  305. AZ::Data::AssetId EditorScriptCanvasComponent::GetAssetId() const
  306. {
  307. return m_scriptCanvasAssetHolder.GetAssetId();
  308. }
  309. AZ::EntityId EditorScriptCanvasComponent::GetGraphEntityId() const
  310. {
  311. AZ::EntityId scriptCanvasEntityId;
  312. AZ::Data::AssetId assetId = m_scriptCanvasAssetHolder.GetAssetId();
  313. if (assetId.IsValid())
  314. {
  315. AssetTrackerRequestBus::BroadcastResult(scriptCanvasEntityId, &AssetTrackerRequests::GetScriptCanvasId, assetId);
  316. }
  317. return scriptCanvasEntityId;
  318. }
  319. void EditorScriptCanvasComponent::OnAssetReady(const ScriptCanvasMemoryAsset::pointer asset)
  320. {
  321. OnScriptCanvasAssetReady(asset);
  322. }
  323. void EditorScriptCanvasComponent::OnAssetSaved(const ScriptCanvasMemoryAsset::pointer asset, bool isSuccessful)
  324. {
  325. if (isSuccessful)
  326. {
  327. OnScriptCanvasAssetReady(asset);
  328. }
  329. }
  330. void EditorScriptCanvasComponent::OnAssetReloaded(const ScriptCanvasMemoryAsset::pointer asset)
  331. {
  332. OnScriptCanvasAssetReady(asset);
  333. }
  334. void EditorScriptCanvasComponent::OnScriptCanvasAssetChanged(AZ::Data::AssetId assetId)
  335. {
  336. AssetTrackerNotificationBus::Handler::BusDisconnect();
  337. ScriptCanvas::GraphIdentifier newIdentifier = GetGraphIdentifier();
  338. newIdentifier.m_assetId = assetId;
  339. ScriptCanvas::GraphIdentifier oldIdentifier = GetGraphIdentifier();
  340. oldIdentifier.m_assetId = m_previousAssetId;
  341. EditorLoggingComponentNotificationBus::Broadcast(&EditorLoggingComponentNotifications::OnAssetSwitched, GetNamedEntityId(), newIdentifier, oldIdentifier);
  342. m_previousAssetId = m_scriptCanvasAssetHolder.GetAssetId();
  343. // Only clear our variables when we are given a new asset id
  344. // or when the asset was explicitly set to empty.
  345. //
  346. // i.e. do not clear variables when we lose the catalog asset.
  347. if ((assetId.IsValid() && assetId != m_removedCatalogId)
  348. || (!assetId.IsValid() && !m_removedCatalogId.IsValid()))
  349. {
  350. ClearVariables();
  351. }
  352. if (assetId.IsValid())
  353. {
  354. AssetTrackerNotificationBus::Handler::BusConnect(assetId);
  355. ScriptCanvasMemoryAsset::pointer memoryAsset;
  356. AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId);
  357. if (memoryAsset && memoryAsset->GetAsset().GetStatus() == AZ::Data::AssetData::AssetStatus::Ready)
  358. {
  359. OnScriptCanvasAssetReady(memoryAsset);
  360. }
  361. }
  362. }
  363. void EditorScriptCanvasComponent::OnStartPlayInEditor()
  364. {
  365. ScriptCanvas::Execution::PerformanceStatisticsEBus::Broadcast(&ScriptCanvas::Execution::PerformanceStatisticsBus::ClearSnaphotStatistics);
  366. }
  367. void EditorScriptCanvasComponent::OnStopPlayInEditor()
  368. {
  369. AZ::ScriptSystemRequestBus::Broadcast(&AZ::ScriptSystemRequests::GarbageCollect);
  370. }
  371. void EditorScriptCanvasComponent::SetAssetId(const AZ::Data::AssetId& assetId)
  372. {
  373. if (m_scriptCanvasAssetHolder.GetAssetId() != assetId)
  374. {
  375. // Invalidate the previously removed catalog id if we are setting a new asset id
  376. m_removedCatalogId.SetInvalid();
  377. SetPrimaryAsset(assetId);
  378. }
  379. }
  380. bool EditorScriptCanvasComponent::HasAssetId() const
  381. {
  382. return m_scriptCanvasAssetHolder.GetAssetId().IsValid();
  383. }
  384. ScriptCanvas::GraphIdentifier EditorScriptCanvasComponent::GetGraphIdentifier() const
  385. {
  386. // For now we don't want to deal with disambiguating duplicates of the same script running on one entity.
  387. // Should that change we need to add the component id back into this.
  388. return ScriptCanvas::GraphIdentifier(m_scriptCanvasAssetHolder.GetAssetId(), 0);
  389. }
  390. void EditorScriptCanvasComponent::OnScriptCanvasAssetReady(const ScriptCanvasMemoryAsset::pointer memoryAsset)
  391. {
  392. if (memoryAsset->GetFileAssetId() == m_scriptCanvasAssetHolder.GetAssetId())
  393. {
  394. LoadVariables(memoryAsset);
  395. UpdateName();
  396. }
  397. }
  398. /*! Start Variable Block Implementation */
  399. void EditorScriptCanvasComponent::AddVariable(AZStd::string_view varName, const ScriptCanvas::GraphVariable& graphVariable)
  400. {
  401. // We only add component properties to the component
  402. if (!graphVariable.IsComponentProperty())
  403. {
  404. return;
  405. }
  406. const auto& variableId = graphVariable.GetVariableId();
  407. ScriptCanvas::EditableVariableConfiguration* originalVarNameValuePair = m_editableData.FindVariable(variableId);
  408. if (!originalVarNameValuePair)
  409. {
  410. m_editableData.AddVariable(varName, graphVariable);
  411. originalVarNameValuePair = m_editableData.FindVariable(variableId);
  412. }
  413. if (!originalVarNameValuePair)
  414. {
  415. AZ_Error("Script Canvas", false, "Unable to find variable with id %s and name %s on the ScriptCanvas Component. There is an issue in AddVariable",
  416. variableId.ToString().data(), varName.data());
  417. return;
  418. }
  419. // Update the variable name as it may have changed
  420. originalVarNameValuePair->m_graphVariable.SetVariableName(varName);
  421. originalVarNameValuePair->m_graphVariable.SetExposureCategory(graphVariable.GetExposureCategory());
  422. originalVarNameValuePair->m_graphVariable.SetScriptInputControlVisibility(AZ::Edit::PropertyVisibility::Hide);
  423. originalVarNameValuePair->m_graphVariable.SetAllowSignalOnChange(false);
  424. }
  425. void EditorScriptCanvasComponent::AddNewVariables(const ScriptCanvas::VariableData& graphVarData)
  426. {
  427. for (auto&& variablePair : graphVarData.GetVariables())
  428. {
  429. AddVariable(variablePair.second.GetVariableName(), variablePair.second);
  430. }
  431. }
  432. void EditorScriptCanvasComponent::RemoveVariable(const ScriptCanvas::VariableId& varId)
  433. {
  434. m_editableData.RemoveVariable(varId);
  435. }
  436. void EditorScriptCanvasComponent::RemoveOldVariables(const ScriptCanvas::VariableData& graphVarData)
  437. {
  438. AZStd::vector<ScriptCanvas::VariableId> oldVariableIds;
  439. for (auto varConfig : m_editableData.GetVariables())
  440. {
  441. const auto& variableId = varConfig.m_graphVariable.GetVariableId();
  442. // We only add component sourced graph properties to the script canvas component, so if this variable was switched to a graph-only property remove it.
  443. // Also be sure to remove this variable if it's been deleted entirely.
  444. auto graphVariable = graphVarData.FindVariable(variableId);
  445. if (!graphVariable || !graphVariable->IsComponentProperty())
  446. {
  447. oldVariableIds.push_back(variableId);
  448. }
  449. }
  450. for (const auto& oldVariableId : oldVariableIds)
  451. {
  452. RemoveVariable(oldVariableId);
  453. }
  454. }
  455. bool EditorScriptCanvasComponent::UpdateVariable(const ScriptCanvas::GraphVariable& graphDatum, ScriptCanvas::GraphVariable& updateDatum, ScriptCanvas::GraphVariable& originalDatum)
  456. {
  457. // If the editable datum is the different than the original datum, then the "variable value" has been overridden on this component
  458. // Variable values only propagate from the Script Canvas graph to this component if the original "variable value" has not been overridden
  459. // by the editable "variable value" on this component and the "variable value" on the graph is different than the variable value on this component
  460. auto isNotOverridden = (*updateDatum.GetDatum()) == (*originalDatum.GetDatum());
  461. auto scGraphIsModified = (*originalDatum.GetDatum()) != (*graphDatum.GetDatum());
  462. if (isNotOverridden && scGraphIsModified)
  463. {
  464. ScriptCanvas::ModifiableDatumView originalDatumView;
  465. originalDatum.ConfigureDatumView(originalDatumView);
  466. originalDatumView.AssignToDatum((*graphDatum.GetDatum()));
  467. ScriptCanvas::ModifiableDatumView updatedDatumView;
  468. updateDatum.ConfigureDatumView(updatedDatumView);
  469. updatedDatumView.AssignToDatum((*graphDatum.GetDatum()));
  470. return true;
  471. }
  472. return false;
  473. }
  474. void EditorScriptCanvasComponent::LoadVariables(const ScriptCanvasMemoryAsset::pointer memoryAsset)
  475. {
  476. auto assetData = memoryAsset->GetAsset();
  477. AZ::Entity* scriptCanvasEntity = assetData->GetScriptCanvasEntity();
  478. AZ_Assert(scriptCanvasEntity, "This graph must have a valid entity");
  479. auto variableComponent = scriptCanvasEntity ? AZ::EntityUtils::FindFirstDerivedComponent<ScriptCanvas::GraphVariableManagerComponent>(scriptCanvasEntity) : nullptr;
  480. if (variableComponent)
  481. {
  482. // Add properties from the SC Asset to the SC Component if they do not exist on the SC Component
  483. AddNewVariables(*variableComponent->GetVariableData());
  484. RemoveOldVariables(*variableComponent->GetVariableData());
  485. }
  486. AzToolsFramework::ToolsApplicationNotificationBus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree_NewContent);
  487. }
  488. void EditorScriptCanvasComponent::ClearVariables()
  489. {
  490. m_editableData.Clear();
  491. }
  492. /* End Variable Block Implementation*/
  493. }