ScriptCanvasBuilderDataSystem.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  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/Asset/AssetSerializer.h>
  9. #include <AzCore/Script/ScriptSystemBus.h>
  10. #include <AzToolsFramework/API/EditorAssetSystemAPI.h>
  11. #include <Builder/ScriptCanvasBuilder.h>
  12. #include <Builder/ScriptCanvasBuilderDataSystem.h>
  13. #include <Builder/ScriptCanvasBuilderWorker.h>
  14. #include <ScriptCanvas/Asset/RuntimeAsset.h>
  15. #include <ScriptCanvas/Assets/ScriptCanvasFileHandling.h>
  16. #include <ScriptCanvas/Components/EditorDeprecationData.h>
  17. #include <ScriptCanvas/Components/EditorGraph.h>
  18. #include <ScriptCanvas/Components/EditorGraphVariableManagerComponent.h>
  19. #include <ScriptCanvas/Grammar/AbstractCodeModel.h>
  20. namespace ScriptCanvasBuilderDataSystemCpp
  21. {
  22. bool IsScriptCanvasFile(AZStd::string_view candidate)
  23. {
  24. AZ::IO::Path path(candidate);
  25. return path.HasExtension() && path.Extension() == ".scriptcanvas";
  26. }
  27. AZStd::optional<AZ::Uuid> GetUuid(AZStd::string_view candidate)
  28. {
  29. AZStd::string watchFolder;
  30. AZ::Data::AssetInfo assetInfo;
  31. bool result = false;
  32. AzToolsFramework::AssetSystemRequestBus::BroadcastResult
  33. ( result
  34. , &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath
  35. , candidate.data()
  36. , assetInfo
  37. , watchFolder);
  38. return assetInfo.m_assetId.m_guid;
  39. }
  40. }
  41. namespace ScriptCanvasBuilder
  42. {
  43. using namespace ScriptCanvasBuilderDataSystemCpp;
  44. DataSystem::DataSystem()
  45. {
  46. AzFramework::AssetSystemInfoBus::Handler::BusConnect();
  47. AzFramework::AssetCatalogEventBus::Handler::BusConnect();
  48. DataSystemAssetRequestsBus::Handler::BusConnect();
  49. DataSystemSourceRequestsBus::Handler::BusConnect();
  50. AzToolsFramework::AssetSystemBus::Handler::BusConnect();
  51. }
  52. DataSystem::~DataSystem()
  53. {
  54. DataSystemAssetRequestsBus::Handler::BusDisconnect();
  55. DataSystemSourceRequestsBus::Handler::BusDisconnect();
  56. AzToolsFramework::AssetSystemBus::Handler::BusDisconnect();
  57. AZ::Data::AssetBus::MultiHandler::BusDisconnect();
  58. AzFramework::AssetSystemInfoBus::Handler::BusDisconnect();
  59. AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
  60. }
  61. void DataSystem::AddResult(const SourceHandle& handle, BuilderSourceStorage&& result)
  62. {
  63. MutexLock lock(m_mutex);
  64. m_buildResultsByHandle[handle.Id()] = result;
  65. }
  66. void DataSystem::AddResult(AZ::Uuid&& id, BuilderSourceStorage&& result)
  67. {
  68. MutexLock lock(m_mutex);
  69. m_buildResultsByHandle[id] = result;
  70. }
  71. BuilderSourceResult DataSystem::CompileBuilderData(SourceHandle sourceHandle)
  72. {
  73. MutexLock lock(m_mutex);
  74. if (!m_buildResultsByHandle.contains(sourceHandle.Id()))
  75. {
  76. CompileBuilderDataInternal(sourceHandle);
  77. }
  78. BuilderSourceStorage& storage = m_buildResultsByHandle[sourceHandle.Id()];
  79. return BuilderSourceResult{ storage.status, &storage.data };
  80. }
  81. void DataSystem::CompileBuilderDataInternal(SourceHandle sourceHandle)
  82. {
  83. using namespace ScriptCanvasBuilder;
  84. BuilderSourceStorage result;
  85. auto assetTreeOutcome = LoadEditorAssetTree(sourceHandle);
  86. if (!assetTreeOutcome.IsSuccess())
  87. {
  88. AZ_Warning("ScriptCanvas", false
  89. , "DataSystem::CompileBuilderDataInternal failed: %s", assetTreeOutcome.GetError().c_str());
  90. result.status = BuilderSourceStatus::Unloadable;
  91. AddResult(sourceHandle, AZStd::move(result));
  92. return;
  93. }
  94. auto parseOutcome = ParseEditorAssetTree(assetTreeOutcome.GetValue());
  95. if (!parseOutcome.IsSuccess())
  96. {
  97. AZ_Warning("ScriptCanvas", false
  98. , "DataSystem::CompileBuilderDataInternal failed: %s", parseOutcome.GetError().c_str());
  99. result.status = BuilderSourceStatus::Failed;
  100. AddResult(sourceHandle, AZStd::move(result));
  101. return;
  102. }
  103. parseOutcome.GetValue().SetHandlesToDescription();
  104. result.data = parseOutcome.TakeValue();
  105. result.status = BuilderSourceStatus::Good;
  106. AddResult(sourceHandle, AZStd::move(result));
  107. }
  108. void DataSystem::MarkAssetInError(AZ::Uuid assetIdGuid)
  109. {
  110. auto& buildResult = m_assets[assetIdGuid];
  111. buildResult.data = {};
  112. buildResult.status = BuilderAssetStatus::Error;
  113. DataSystemAssetNotificationsBus::Event
  114. ( assetIdGuid
  115. , &DataSystemAssetNotifications::OnAssetNotReady);
  116. DATA_SYSTEM_STATUS
  117. ( "ScriptCanvas"
  118. , "DataSystem received OnAssetError: %s"
  119. , assetIdGuid.ToString<AZStd::fixed_string<AZ::Uuid::MaxStringBuffer>>().c_str());
  120. }
  121. BuilderAssetResult& DataSystem::MonitorAsset(AZ::Uuid sourceId)
  122. {
  123. const auto assetId = AZ::Data::AssetId(sourceId, ScriptCanvas::RuntimeDataSubId);
  124. AZ::Data::AssetBus::MultiHandler::BusConnect(assetId);
  125. ScriptCanvas::RuntimeAssetPtr asset(assetId, azrtti_typeid<ScriptCanvas::RuntimeAsset>());
  126. asset.SetAutoLoadBehavior(AZ::Data::AssetLoadBehavior::PreLoad);
  127. m_assets[sourceId] = BuilderAssetResult{ BuilderAssetStatus::Pending, asset };
  128. return m_assets[sourceId];
  129. }
  130. BuilderAssetResult DataSystem::LoadAsset(SourceHandle sourceHandle)
  131. {
  132. BuilderAssetResult* result = nullptr;;
  133. if (auto iter = m_assets.find(sourceHandle.Id()); iter != m_assets.end())
  134. {
  135. result = &iter->second;
  136. }
  137. else
  138. {
  139. result = &MonitorAsset(sourceHandle.Id());
  140. }
  141. result->data.QueueLoad();
  142. return *result;
  143. }
  144. void DataSystem::OnAssetError(AZ::Data::Asset<AZ::Data::AssetData> asset)
  145. {
  146. const auto assetIdGuid = asset.GetId().m_guid;
  147. DATA_SYSTEM_STATUS
  148. ( "ScriptCanvas"
  149. , "DataSystem received OnAssetError: %s : %s, marking asset in error"
  150. , asset.GetHint().c_str()
  151. , assetIdGuid.ToString<AZStd::fixed_string<AZ::Uuid::MaxStringBuffer>>().c_str());
  152. MarkAssetInError(assetIdGuid);
  153. }
  154. void DataSystem::OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset)
  155. {
  156. DATA_SYSTEM_STATUS
  157. ( "ScriptCanvas"
  158. , "DataSystem received OnAssetReady: %s : %s, reporting it ready"
  159. , asset.GetHint().c_str()
  160. , asset.GetId().m_guid.ToString<AZStd::fixed_string<AZ::Uuid::MaxStringBuffer>>().c_str());
  161. ReportReadyFilter(asset);
  162. }
  163. void DataSystem::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId)
  164. {
  165. if (assetId.m_subId != ScriptCanvas::RuntimeDataSubId)
  166. {
  167. return;
  168. }
  169. DATA_SYSTEM_STATUS
  170. ( "ScriptCanvas"
  171. , "DataSystem received OnCatalogAssetAdded: %s, monitoring asset"
  172. , assetId.m_guid.ToString<AZStd::fixed_string<AZ::Uuid::MaxStringBuffer>>().c_str());
  173. MonitorAsset(assetId.m_guid).data.QueueLoad();
  174. }
  175. void DataSystem::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId)
  176. {
  177. if (assetId.m_subId != ScriptCanvas::RuntimeDataSubId)
  178. {
  179. return;
  180. }
  181. DATA_SYSTEM_STATUS
  182. ( "ScriptCanvas"
  183. , "DataSystem received OnCatalogAssetChanged: %s, monitoring asset"
  184. , assetId.m_guid.ToString<AZStd::fixed_string<AZ::Uuid::MaxStringBuffer>>().c_str());
  185. MonitorAsset(assetId.m_guid).data.QueueLoad();
  186. }
  187. void DataSystem::OnCatalogAssetRemoved(const AZ::Data::AssetId& assetId, [[maybe_unused]] const AZ::Data::AssetInfo& assetInfo)
  188. {
  189. if (assetId.m_subId != ScriptCanvas::RuntimeDataSubId)
  190. {
  191. return;
  192. }
  193. DATA_SYSTEM_STATUS
  194. ( "ScriptCanvas"
  195. , "DataSystem received OnCatalogAssetRemoved: %s, marking asset in error"
  196. , assetId.m_guid.ToString<AZStd::fixed_string<AZ::Uuid::MaxStringBuffer>>().c_str());
  197. MarkAssetInError(assetId.m_guid);
  198. }
  199. void DataSystem::ReportReady(AZ::Data::Asset<AZ::Data::AssetData> asset)
  200. {
  201. using namespace ScriptCanvas;
  202. const auto assetIdGuid = asset.GetId().m_guid;
  203. auto& buildResult = m_assets[assetIdGuid];
  204. buildResult.data = asset;
  205. buildResult.data.SetAutoLoadBehavior(AZ::Data::AssetLoadBehavior::PreLoad);
  206. DATA_SYSTEM_STATUS("ScriptCanvas", "DataSystem::ReportReady received a runtime asset");
  207. if (auto result = IsPreloaded(buildResult.data); result != IsPreloadedResult::Yes)
  208. {
  209. AZ_Error("ScriptCanvas"
  210. , false
  211. , "DataSystem received ready for asset that was not loaded: %s-%s"
  212. , buildResult.data.GetHint().c_str()
  213. , assetIdGuid.ToString<AZStd::fixed_string<AZ::Uuid::MaxStringBuffer>>().c_str()
  214. );
  215. DATA_SYSTEM_STATUS("ScriptCanvas", "DataSystem::ReportReady received a runtime asset, but it was not pre-loaded");
  216. buildResult.status = BuilderAssetStatus::Error;
  217. DataSystemAssetNotificationsBus::Event
  218. ( assetIdGuid
  219. , &DataSystemAssetNotifications::OnAssetNotReady);
  220. }
  221. else
  222. {
  223. DATA_SYSTEM_STATUS("ScriptCanvas", "DataSystem::ReportReady received a runtime asset and it is ready");
  224. buildResult.status = BuilderAssetStatus::Ready;
  225. DataSystemAssetNotificationsBus::Event
  226. ( assetIdGuid
  227. , &DataSystemAssetNotifications::OnReady
  228. , buildResult.data);
  229. }
  230. }
  231. void DataSystem::ReportReadyFilter(AZ::Data::Asset<AZ::Data::AssetData> asset)
  232. {
  233. using namespace ScriptCanvas;
  234. DATA_SYSTEM_STATUS("ScriptCanvas", "DataSystem::ReportReadyFilter received a runtime asset, queuing Lua script processing.");
  235. SCRIPT_SYSTEM_SCRIPT_STATUS("ScriptCanvas", "DataSystem::ReportReadyFilter received a runtime asset, queuing Lua script processing.");
  236. AZ::SystemTickBus::QueueFunction([this, asset]()
  237. {
  238. DATA_SYSTEM_STATUS("ScriptCanvas", "DataSystem::ReportReadyFilter executing Lua script processing.");
  239. SCRIPT_SYSTEM_SCRIPT_STATUS("ScriptCanvas", "DataSystem::ReportReadyFilter executing Lua script processing.");
  240. const auto assetIdGuid = asset.GetId().m_guid;
  241. auto& buildResult = m_assets[assetIdGuid];
  242. buildResult.data = asset;
  243. buildResult.data.SetAutoLoadBehavior(AZ::Data::AssetLoadBehavior::PreLoad);
  244. auto& luaAsset = buildResult.data.Get()->m_runtimeData.m_script;
  245. luaAsset
  246. = AZ::Data::AssetManager::Instance().GetAsset<AZ::ScriptAsset>(luaAsset.GetId(), AZ::Data::AssetLoadBehavior::PreLoad, {});
  247. luaAsset.QueueLoad();
  248. luaAsset.BlockUntilLoadComplete();
  249. ReportReady(buildResult.data);
  250. });
  251. }
  252. void DataSystem::OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset)
  253. {
  254. DATA_SYSTEM_STATUS
  255. ( "ScriptCanvas"
  256. , "DataSystem received OnAssetReloaded: %s : %s"
  257. , asset.GetHint().c_str()
  258. , asset.GetId().m_guid.ToString<AZStd::fixed_string<AZ::Uuid::MaxStringBuffer>>().c_str());
  259. ReportReadyFilter(asset);
  260. }
  261. void DataSystem::OnAssetUnloaded(const AZ::Data::AssetId assetId, [[maybe_unused]] const AZ::Data::AssetType assetType)
  262. {
  263. DataSystemAssetNotificationsBus::Event(assetId.m_guid, &DataSystemAssetNotifications::OnAssetNotReady);
  264. MonitorAsset(assetId.m_guid);
  265. }
  266. void DataSystem::SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid sourceId)
  267. {
  268. if (!IsScriptCanvasFile(relativePath))
  269. {
  270. return;
  271. }
  272. SCRIPT_SYSTEM_SCRIPT_STATUS
  273. ( "ScriptCanvas"
  274. , "DataSystem received source file changed: %s : %s"
  275. , relativePath.c_str()
  276. , sourceId.ToString<AZStd::fixed_string<AZ::Uuid::MaxStringBuffer>>().c_str());
  277. DataSystemAssetNotificationsBus::Event(sourceId, &DataSystemAssetNotifications::OnAssetNotReady);
  278. MonitorAsset(sourceId);
  279. auto handle = SourceHandle::FromRelativePathAndScanFolder(relativePath, scanFolder, sourceId);
  280. CompileBuilderDataInternal(handle);
  281. auto& builderStorage = m_buildResultsByHandle[sourceId];
  282. DataSystemSourceNotificationsBus::Event
  283. ( sourceId
  284. , &DataSystemSourceNotifications::SourceFileChanged
  285. , BuilderSourceResult{ builderStorage.status, &builderStorage.data }
  286. , relativePath
  287. , scanFolder);
  288. }
  289. void DataSystem::SourceFileRemoved(AZStd::string relativePath, [[maybe_unused]] AZStd::string scanFolder, AZ::Uuid sourceId)
  290. {
  291. if (!IsScriptCanvasFile(relativePath))
  292. {
  293. return;
  294. }
  295. BuilderSourceStorage result;
  296. result.status = BuilderSourceStatus::Removed;
  297. AddResult(AZStd::move(sourceId), AZStd::move(result));
  298. DataSystemSourceNotificationsBus::Event
  299. ( sourceId
  300. , &DataSystemSourceNotifications::SourceFileRemoved
  301. , relativePath
  302. , scanFolder);
  303. }
  304. void DataSystem::SourceFileFailed(AZStd::string relativePath, [[maybe_unused]] AZStd::string scanFolder, AZ::Uuid sourceId)
  305. {
  306. if (!IsScriptCanvasFile(relativePath))
  307. {
  308. return;
  309. }
  310. BuilderSourceStorage result;
  311. result.status = BuilderSourceStatus::Failed;
  312. AddResult(AZStd::move(sourceId), AZStd::move(result));
  313. DataSystemSourceNotificationsBus::Event
  314. ( sourceId
  315. , &DataSystemSourceNotifications::SourceFileFailed
  316. , relativePath
  317. , scanFolder);
  318. }
  319. }