PrefabGroupBehavior.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  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 <PrefabGroup/PrefabGroupBehavior.h>
  9. #include <PrefabGroup/PrefabGroup.h>
  10. #include <PrefabGroup/ProceduralAssetHandler.h>
  11. #include <PrefabGroup/DefaultProceduralPrefab.h>
  12. #include <AzCore/Asset/AssetManagerBus.h>
  13. #include <AzCore/Component/TransformBus.h>
  14. #include <AzCore/IO/FileIO.h>
  15. #include <AzCore/IO/Path/Path.h>
  16. #include <AzCore/JSON/document.h>
  17. #include <AzCore/JSON/error/en.h>
  18. #include <AzCore/JSON/error/error.h>
  19. #include <AzCore/JSON/prettywriter.h>
  20. #include <AzCore/JSON/stringbuffer.h>
  21. #include <AzCore/Serialization/SerializeContext.h>
  22. #include <AzCore/Settings/SettingsRegistry.h>
  23. #include <AzCore/std/smart_ptr/make_shared.h>
  24. #include <AzToolsFramework/API/EditorAssetSystemAPI.h>
  25. #include <AzToolsFramework/Component/EditorComponentAPIBus.h>
  26. #include <AzToolsFramework/Entity/EntityUtilityComponent.h>
  27. #include <AzToolsFramework/Prefab/Instance/InstanceToTemplateInterface.h>
  28. #include <AzToolsFramework/Prefab/PrefabLoaderInterface.h>
  29. #include <AzToolsFramework/Prefab/PrefabLoaderScriptingBus.h>
  30. #include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
  31. #include <AzToolsFramework/Prefab/PrefabSystemScriptingBus.h>
  32. #include <AzToolsFramework/Prefab/Procedural/ProceduralPrefabAsset.h>
  33. #include <AzToolsFramework/ToolsComponents/TransformComponent.h>
  34. #include <SceneAPI/SceneCore/Components/ExportingComponent.h>
  35. #include <SceneAPI/SceneCore/Containers/Scene.h>
  36. #include <SceneAPI/SceneCore/Containers/SceneManifest.h>
  37. #include <SceneAPI/SceneCore/Containers/Views/SceneGraphDownwardsIterator.h>
  38. #include <SceneAPI/SceneCore/Containers/Views/SceneGraphUpwardsIterator.h>
  39. #include <SceneAPI/SceneCore/DataTypes/DataTypeUtilities.h>
  40. #include <SceneAPI/SceneCore/DataTypes/GraphData/ICustomPropertyData.h>
  41. #include <SceneAPI/SceneCore/DataTypes/GraphData/IMeshData.h>
  42. #include <SceneAPI/SceneCore/DataTypes/GraphData/ITransform.h>
  43. #include <SceneAPI/SceneCore/Events/AssetImportRequest.h>
  44. #include <SceneAPI/SceneCore/Events/ExportEventContext.h>
  45. #include <SceneAPI/SceneCore/Events/ExportProductList.h>
  46. #include <SceneAPI/SceneCore/Utilities/FileUtilities.h>
  47. #include <SceneAPI/SceneData/Groups/MeshGroup.h>
  48. #include <SceneAPI/SceneData/Rules/CoordinateSystemRule.h>
  49. #include <SceneAPI/SceneData/Rules/LodRule.h>
  50. #include <SceneAPI/SceneCore/Events/ManifestMetaInfoBus.h>
  51. #include <SceneAPI/SceneCore/Containers/Utilities/SceneGraphUtilities.h>
  52. namespace AZ::SceneAPI::Behaviors
  53. {
  54. //
  55. // ExportEventHandler
  56. //
  57. static constexpr const char s_PrefabGroupBehaviorCreateDefaultKey[] = "/O3DE/Preferences/Prefabs/CreateDefaults";
  58. static constexpr const char s_PrefabGroupBehaviorIgnoreActorsKey[] = "/O3DE/Preferences/Prefabs/IgnoreActors";
  59. struct PrefabGroupBehavior::ExportEventHandler final
  60. : public AZ::SceneAPI::SceneCore::ExportingComponent
  61. , public Events::AssetImportRequestBus::Handler
  62. , public Events::ManifestMetaInfoBus::Handler
  63. {
  64. AZ_CLASS_ALLOCATOR(PrefabGroupBehavior, AZ::SystemAllocator)
  65. using PreExportEventContextFunction = AZStd::function<Events::ProcessingResult(Events::PreExportEventContext&)>;
  66. PreExportEventContextFunction m_preExportEventContextFunction;
  67. AZ::Prefab::PrefabGroupAssetHandler m_prefabGroupAssetHandler;
  68. AZStd::unique_ptr<DefaultProceduralPrefabGroup> m_defaultProceduralPrefab;
  69. ExportEventHandler() = delete;
  70. ExportEventHandler(PreExportEventContextFunction function)
  71. : m_preExportEventContextFunction(AZStd::move(function))
  72. {
  73. m_defaultProceduralPrefab = AZStd::make_unique<DefaultProceduralPrefabGroup>();
  74. BindToCall(&ExportEventHandler::PrepareForExport);
  75. AZ::SceneAPI::SceneCore::ExportingComponent::Activate();
  76. Events::AssetImportRequestBus::Handler::BusConnect();
  77. Events::ManifestMetaInfoBus::Handler::BusConnect();
  78. }
  79. ~ExportEventHandler()
  80. {
  81. m_defaultProceduralPrefab.reset();
  82. Events::ManifestMetaInfoBus::Handler::BusDisconnect();
  83. Events::AssetImportRequestBus::Handler::BusDisconnect();
  84. AZ::SceneAPI::SceneCore::ExportingComponent::Deactivate();
  85. }
  86. Events::ProcessingResult PrepareForExport(Events::PreExportEventContext& context)
  87. {
  88. return m_preExportEventContextFunction(context);
  89. }
  90. Events::ProcessingResult UpdateSceneForPrefabGroup(Containers::Scene& scene, ManifestAction action);
  91. // AssetImportRequest
  92. Events::ProcessingResult UpdateManifest(Containers::Scene& scene, ManifestAction action, RequestingApplication requester) override;
  93. Events::ProcessingResult PrepareForAssetLoading(Containers::Scene& scene, RequestingApplication requester) override;
  94. void GetPolicyName(AZStd::string& result) const override
  95. {
  96. result = "PrefabGroupBehavior::ExportEventHandler";
  97. }
  98. // ManifestMetaInfoBus
  99. void GetCategoryAssignments(AZ::SceneAPI::Events::ManifestMetaInfo::CategoryRegistrationList& categories, const Containers::Scene& scene) override;
  100. void InitializeObject(const Containers::Scene& scene, DataTypes::IManifestObject& target) override;
  101. };
  102. Events::ProcessingResult PrefabGroupBehavior::ExportEventHandler::PrepareForAssetLoading(
  103. [[maybe_unused]] Containers::Scene& scene,
  104. RequestingApplication requester)
  105. {
  106. using namespace AzToolsFramework;
  107. if (requester == RequestingApplication::AssetProcessor)
  108. {
  109. EntityUtilityBus::Broadcast(&EntityUtilityBus::Events::ResetEntityContext);
  110. AZ::Interface<AzToolsFramework::Prefab::PrefabSystemComponentInterface>::Get()->RemoveAllTemplates();
  111. }
  112. return Events::ProcessingResult::Success;
  113. }
  114. void PrefabGroupBehavior::ExportEventHandler::GetCategoryAssignments(CategoryRegistrationList& categories, const Containers::Scene&)
  115. {
  116. categories.emplace_back("Procedural Prefab", SceneData::PrefabGroup::TYPEINFO_Uuid(), s_prefabGroupPreferredTabOrder);
  117. }
  118. Events::ProcessingResult PrefabGroupBehavior::ExportEventHandler::UpdateSceneForPrefabGroup(
  119. Containers::Scene& scene,
  120. ManifestAction action)
  121. {
  122. if (AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry)
  123. {
  124. bool skip = false;
  125. // this toggle makes constructing default mesh groups and a prefab optional
  126. bool createDefaultPrefab = true;
  127. settingsRegistry->Get(createDefaultPrefab, s_PrefabGroupBehaviorCreateDefaultKey);
  128. if (createDefaultPrefab == false)
  129. {
  130. AZ_Info(
  131. "PrefabGroupBehavior",
  132. "Skipping default prefab generation - registry setting %s is disabled\n",
  133. s_PrefabGroupBehaviorCreateDefaultKey);
  134. skip = true;
  135. }
  136. // do not make a Prefab Group if the animation policy will be applied (if ignore actors is set)
  137. bool ignoreActors = true;
  138. settingsRegistry->Get(ignoreActors, s_PrefabGroupBehaviorIgnoreActorsKey);
  139. if (!skip && ignoreActors)
  140. {
  141. AZStd::set<AZStd::string> appliedPolicies;
  142. AZ::SceneAPI::Events::GraphMetaInfoBus::Broadcast(
  143. &AZ::SceneAPI::Events::GraphMetaInfoBus::Events::GetAppliedPolicyNames,
  144. appliedPolicies,
  145. scene);
  146. if (appliedPolicies.contains("ActorGroupBehavior"))
  147. {
  148. AZ_Info(
  149. "PrefabGroupBehavior",
  150. "Skipping default prefab generation - scene has an Actor group present and registry setting %s"
  151. " is enabled\n",
  152. s_PrefabGroupBehaviorIgnoreActorsKey);
  153. skip = true;
  154. }
  155. }
  156. // Remove the prefab group so it doesn't try fail to process an empty prefab group during export
  157. if (skip)
  158. {
  159. for (auto manifestItemIdx = 0; manifestItemIdx < scene.GetManifest().GetEntryCount(); ++manifestItemIdx)
  160. {
  161. const auto* prefabGroup =
  162. azrtti_cast<const SceneData::PrefabGroup*>(scene.GetManifest().GetValue(manifestItemIdx).get());
  163. if (prefabGroup)
  164. {
  165. if (prefabGroup->GetPrefabDomRef().has_value() == false)
  166. {
  167. scene.GetManifest().RemoveEntry(prefabGroup);
  168. return Events::ProcessingResult::Ignored;
  169. }
  170. }
  171. }
  172. return Events::ProcessingResult::Ignored;
  173. }
  174. }
  175. if (action == Events::AssetImportRequest::Update)
  176. {
  177. bool createProceduralPrefab = false;
  178. for (auto manifestItemIdx = 0; manifestItemIdx < scene.GetManifest().GetEntryCount(); ++manifestItemIdx)
  179. {
  180. const auto* prefabGroup = azrtti_cast<const SceneData::PrefabGroup*>(scene.GetManifest().GetValue(manifestItemIdx).get());
  181. if (prefabGroup)
  182. {
  183. // found a Prefab Group that wants to be created but does not have a DOM yet?
  184. if (prefabGroup->GetPrefabDomRef().has_value() == false)
  185. {
  186. // re-create the Prefab Group to get the DOM
  187. scene.GetManifest().RemoveEntry(prefabGroup);
  188. createProceduralPrefab = true;
  189. break;
  190. }
  191. }
  192. }
  193. if (createProceduralPrefab)
  194. {
  195. // clear out the previous created default mesh groups made for this prefab group
  196. AZStd::vector<const DataTypes::IMeshGroup*> proceduralMeshGroupList;
  197. for (auto manifestItemIdx = 0; manifestItemIdx < scene.GetManifest().GetEntryCount(); ++manifestItemIdx)
  198. {
  199. auto* meshGroup = azrtti_cast<DataTypes::IMeshGroup*>(scene.GetManifest().GetValue(manifestItemIdx).get());
  200. if (meshGroup)
  201. {
  202. const auto proceduralMeshGroupRule =
  203. meshGroup->GetRuleContainer().FindFirstByType<SceneData::ProceduralMeshGroupRule>();
  204. if (proceduralMeshGroupRule)
  205. {
  206. proceduralMeshGroupList.push_back(meshGroup);
  207. }
  208. }
  209. }
  210. while (!proceduralMeshGroupList.empty())
  211. {
  212. scene.GetManifest().RemoveEntry(proceduralMeshGroupList.back());
  213. proceduralMeshGroupList.pop_back();
  214. }
  215. }
  216. else
  217. {
  218. // if a valid prefab group has already been created then do not generate another prefab group
  219. return Events::ProcessingResult::Ignored;
  220. }
  221. }
  222. // ignore empty scenes (i.e. only has the root node)
  223. if (scene.GetGraph().GetNodeCount() == 1)
  224. {
  225. return Events::ProcessingResult::Ignored;
  226. }
  227. AZStd::optional<AZ::SceneAPI::PrefabGroupRequests::ManifestUpdates> manifestUpdates;
  228. AZ::SceneAPI::PrefabGroupEventBus::BroadcastResult(
  229. manifestUpdates, &AZ::SceneAPI::PrefabGroupEventBus::Events::GeneratePrefabGroupManifestUpdates, scene);
  230. if (!manifestUpdates)
  231. {
  232. AZ_Warning("prefab", false, "Scene doesn't contain IMeshData, add at least 1 IMeshData to generate Manifest Updates");
  233. return Events::ProcessingResult::Ignored;
  234. }
  235. // update manifest if there were no errors
  236. for (auto update : manifestUpdates.value())
  237. {
  238. scene.GetManifest().AddEntry(update);
  239. }
  240. return Events::ProcessingResult::Success;
  241. }
  242. Events::ProcessingResult PrefabGroupBehavior::ExportEventHandler::UpdateManifest(
  243. Containers::Scene& scene,
  244. ManifestAction action,
  245. [[maybe_unused]] RequestingApplication requester)
  246. {
  247. return UpdateSceneForPrefabGroup(scene, action);
  248. }
  249. void PrefabGroupBehavior::ExportEventHandler::InitializeObject(const Containers::Scene& scene, DataTypes::IManifestObject& target)
  250. {
  251. if (!target.RTTI_IsTypeOf(PrefabGroup::TYPEINFO_Uuid()))
  252. {
  253. return;
  254. }
  255. AZStd::vector<AZStd::shared_ptr<DataTypes::IManifestObject>> manifestUpdates;
  256. AZ::SceneAPI::PrefabGroupEventBus::BroadcastResult(
  257. manifestUpdates, &AZ::SceneAPI::PrefabGroupEventBus::Events::GenerateDefaultPrefabMeshGroups, scene);
  258. Events::ManifestMetaInfoBus::Broadcast(&Events::ManifestMetaInfoBus::Events::AddObjects, manifestUpdates);
  259. }
  260. //
  261. // PrefabGroupBehavior
  262. //
  263. void PrefabGroupBehavior::Activate()
  264. {
  265. m_exportEventHandler = AZStd::make_shared<ExportEventHandler>([this](auto& context)
  266. {
  267. return this->OnPrepareForExport(context);
  268. });
  269. }
  270. void PrefabGroupBehavior::Deactivate()
  271. {
  272. m_exportEventHandler.reset();
  273. }
  274. AZStd::unique_ptr<rapidjson::Document> PrefabGroupBehavior::CreateProductAssetData(const SceneData::PrefabGroup* prefabGroup, const AZ::IO::Path& relativePath) const
  275. {
  276. using namespace AzToolsFramework::Prefab;
  277. auto* prefabLoaderInterface = AZ::Interface<PrefabLoaderInterface>::Get();
  278. if (!prefabLoaderInterface)
  279. {
  280. AZ_Error("prefab", false, "Could not get PrefabLoaderInterface");
  281. return {};
  282. }
  283. // write to a UTF-8 string buffer
  284. auto prefabDomRef = prefabGroup->GetPrefabDomRef();
  285. if (!prefabDomRef)
  286. {
  287. AZ_Error("prefab", false, "PrefabGroup(%s) missing PrefabDom", prefabGroup->GetName().c_str());
  288. return {};
  289. }
  290. const AzToolsFramework::Prefab::PrefabDom& prefabDom = prefabDomRef.value();
  291. rapidjson::StringBuffer sb;
  292. rapidjson::Writer<rapidjson::StringBuffer, rapidjson::UTF8<>> writer(sb);
  293. if (prefabDom.Accept(writer) == false)
  294. {
  295. AZ_Error("prefab", false, "Could not write PrefabGroup(%s) to JSON", prefabGroup->GetName().c_str());
  296. return {};
  297. }
  298. // The originPath we pass to LoadTemplateFromString must be the relative path of the file
  299. AZ::IO::Path templateName(prefabGroup->GetName());
  300. templateName.ReplaceExtension(AZ::Prefab::PrefabGroupAssetHandler::s_Extension);
  301. if (!AZ::StringFunc::StartsWith(templateName.c_str(), relativePath.c_str()))
  302. {
  303. templateName = relativePath / templateName;
  304. }
  305. auto templateId = prefabLoaderInterface->LoadTemplateFromString(sb.GetString(), templateName.Native().c_str());
  306. if (templateId == InvalidTemplateId)
  307. {
  308. AZ_Error("prefab", false, "PrefabGroup(%s) Could not load template", prefabGroup->GetName().c_str());
  309. return {};
  310. }
  311. auto* prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
  312. if (!prefabSystemComponentInterface)
  313. {
  314. AZ_Error("prefab", false, "Could not get PrefabSystemComponentInterface");
  315. return {};
  316. }
  317. const rapidjson::Document& generatedInstanceDom = prefabSystemComponentInterface->FindTemplateDom(templateId);
  318. auto proceduralPrefab = AZStd::make_unique<rapidjson::Document>(rapidjson::kObjectType);
  319. proceduralPrefab->CopyFrom(generatedInstanceDom, proceduralPrefab->GetAllocator(), true);
  320. return proceduralPrefab;
  321. }
  322. bool PrefabGroupBehavior::WriteOutProductAsset(
  323. Events::PreExportEventContext& context,
  324. const SceneData::PrefabGroup* prefabGroup,
  325. const rapidjson::Document& doc) const
  326. {
  327. // Since the prefab group name already has the source file extension added as a part of the name (ex: "model_fbx"),
  328. // we won't pass the source file extension again to CreateOuputFileName. This prevents names like "model_fbx.fbx.procprefab".
  329. // CreateOutputFileName has been changed to preserve the model's extension as a bugfix, which occurred after the procprefab
  330. // system was built, so we need to be concerned with backwards compatibility. Procprefab files are typically referenced
  331. // by file name, not by asset ID or source GUID, so we can't introduce changes that would change the procprefab file name.
  332. const AZStd::string emptySourceExtension;
  333. AZStd::string filePath = AZ::SceneAPI::Utilities::FileUtilities::CreateOutputFileName(
  334. prefabGroup->GetName().c_str(),
  335. context.GetOutputDirectory(),
  336. AZ::Prefab::PrefabGroupAssetHandler::s_Extension,
  337. emptySourceExtension);
  338. bool result = WriteOutProductAssetFile(filePath, context, prefabGroup, doc, false);
  339. if (context.GetDebug())
  340. {
  341. AZStd::string debugFilePath = AZ::SceneAPI::Utilities::FileUtilities::CreateOutputFileName(
  342. prefabGroup->GetName().c_str(),
  343. context.GetOutputDirectory(),
  344. AZ::Prefab::PrefabGroupAssetHandler::s_Extension,
  345. emptySourceExtension);
  346. debugFilePath.append(".json");
  347. WriteOutProductAssetFile(debugFilePath, context, prefabGroup, doc, true);
  348. }
  349. return result;
  350. }
  351. bool PrefabGroupBehavior::WriteOutProductAssetFile(
  352. const AZStd::string& filePath,
  353. Events::PreExportEventContext& context,
  354. const SceneData::PrefabGroup* prefabGroup,
  355. const rapidjson::Document& doc,
  356. bool debug) const
  357. {
  358. AZ::IO::FileIOStream fileStream(filePath.c_str(), AZ::IO::OpenMode::ModeWrite);
  359. if (fileStream.IsOpen() == false)
  360. {
  361. AZ_Error("prefab", false, "File path(%s) could not open for write", filePath.c_str());
  362. return false;
  363. }
  364. // write to a UTF-8 string buffer
  365. Data::AssetType assetType = azrtti_typeid<Prefab::ProceduralPrefabAsset>();
  366. AZStd::string productPath {prefabGroup->GetName()};
  367. rapidjson::StringBuffer sb;
  368. bool writerResult = false;
  369. if (debug)
  370. {
  371. rapidjson::PrettyWriter<rapidjson::StringBuffer, rapidjson::UTF8<>> writer(sb);
  372. writerResult = doc.Accept(writer);
  373. productPath.append(".json");
  374. assetType = Data::AssetType::CreateNull();
  375. }
  376. else
  377. {
  378. rapidjson::Writer<rapidjson::StringBuffer, rapidjson::UTF8<>> writer(sb);
  379. writerResult = doc.Accept(writer);
  380. }
  381. if (writerResult == false)
  382. {
  383. AZ_Error("prefab", false, "PrefabGroup(%s) Could not buffer JSON", prefabGroup->GetName().c_str());
  384. return false;
  385. }
  386. const auto bytesWritten = fileStream.Write(sb.GetSize(), sb.GetString());
  387. if (bytesWritten > 1)
  388. {
  389. AZ::u32 subId = AZ::Crc32(productPath.c_str());
  390. context.GetProductList().AddProduct(
  391. filePath,
  392. context.GetScene().GetSourceGuid(),
  393. assetType,
  394. {},
  395. AZStd::make_optional(subId));
  396. return true;
  397. }
  398. return false;
  399. }
  400. Events::ProcessingResult PrefabGroupBehavior::OnPrepareForExport(Events::PreExportEventContext& context) const
  401. {
  402. AZStd::vector<const SceneData::PrefabGroup*> prefabGroupCollection;
  403. const Containers::SceneManifest& manifest = context.GetScene().GetManifest();
  404. for (size_t i = 0; i < manifest.GetEntryCount(); ++i)
  405. {
  406. const auto* group = azrtti_cast<const SceneData::PrefabGroup*>(manifest.GetValue(i).get());
  407. if (group)
  408. {
  409. prefabGroupCollection.push_back(group);
  410. }
  411. }
  412. if (prefabGroupCollection.empty())
  413. {
  414. return AZ::SceneAPI::Events::ProcessingResult::Ignored;
  415. }
  416. // Get the relative path of the source and then take just the path portion of it (no file name)
  417. AZ::IO::Path relativePath = context.GetScene().GetSourceFilename();
  418. relativePath = relativePath.LexicallyRelative(AZStd::string_view(context.GetScene().GetWatchFolder()));
  419. AZStd::string relativeSourcePath { AZStd::move(relativePath.ParentPath().Native()) };
  420. AZ::StringFunc::Replace(relativeSourcePath, "\\", "/"); // the source paths use forward slashes
  421. for (const auto* prefabGroup : prefabGroupCollection)
  422. {
  423. auto result = CreateProductAssetData(prefabGroup, relativeSourcePath);
  424. if (!result)
  425. {
  426. return Events::ProcessingResult::Failure;
  427. }
  428. if (WriteOutProductAsset(context, prefabGroup, *result.get()) == false)
  429. {
  430. return Events::ProcessingResult::Failure;
  431. }
  432. }
  433. return Events::ProcessingResult::Success;
  434. }
  435. void PrefabGroupBehavior::Reflect(ReflectContext* context)
  436. {
  437. AZ::SceneAPI::SceneData::PrefabGroup::Reflect(context);
  438. Prefab::ProceduralPrefabAsset::Reflect(context);
  439. DefaultProceduralPrefabGroup::Reflect(context);
  440. SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
  441. if (serializeContext)
  442. {
  443. serializeContext->Class<PrefabGroupBehavior, BehaviorComponent>()->Version(2);
  444. }
  445. BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context);
  446. if (behaviorContext)
  447. {
  448. auto loadTemplate = [](const AZStd::string& prefabPath)
  449. {
  450. AZ::IO::FixedMaxPath path {prefabPath};
  451. auto* prefabLoaderInterface = AZ::Interface<AzToolsFramework::Prefab::PrefabLoaderInterface>::Get();
  452. if (prefabLoaderInterface)
  453. {
  454. return prefabLoaderInterface->LoadTemplateFromFile(path);
  455. }
  456. return AzToolsFramework::Prefab::TemplateId{};
  457. };
  458. behaviorContext->Method("LoadTemplate", loadTemplate)
  459. ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
  460. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
  461. ->Attribute(AZ::Script::Attributes::Module, "prefab");
  462. auto saveTemplateToString = [](AzToolsFramework::Prefab::TemplateId templateId) -> AZStd::string
  463. {
  464. AZStd::string output;
  465. auto* prefabLoaderInterface = AZ::Interface<AzToolsFramework::Prefab::PrefabLoaderInterface>::Get();
  466. if (prefabLoaderInterface)
  467. {
  468. prefabLoaderInterface->SaveTemplateToString(templateId, output);
  469. }
  470. return output;
  471. };
  472. behaviorContext->Method("SaveTemplateToString", saveTemplateToString)
  473. ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
  474. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
  475. ->Attribute(AZ::Script::Attributes::Module, "prefab");
  476. }
  477. }
  478. }