PrefabUpdateTemplateTests.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  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/Component/TransformBus.h>
  9. #include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
  10. #include <AzToolsFramework/Prefab/PrefabDomUtils.h>
  11. #include <Prefab/PrefabTestComponent.h>
  12. #include <Prefab/PrefabTestDomUtils.h>
  13. #include <Prefab/PrefabTestFixture.h>
  14. namespace UnitTest
  15. {
  16. using PrefabUpdateTemplateTest = PrefabTestFixture;
  17. /*
  18. The below tests use an example of car->axle->wheel templates to test that change propagation works correctly within templates.
  19. The car template will have axle templates nested under it and the axle template will have wheel templates nested under it.
  20. Because of the complexity that arises from multiple levels of prefab nesting, it's easier to write tests using an example scenario
  21. than use generic nesting terminology.
  22. */
  23. TEST_F(PrefabUpdateTemplateTest, UpdatePrefabTemplate_AddEntity_AllDependentTemplatesUpdated)
  24. {
  25. // Create a single entity wheel instance and create a template out of it.
  26. AZ::Entity* wheelEntity = CreateEntity("WheelEntity1");
  27. AZStd::unique_ptr<Instance> wheelIsolatedInstance = m_prefabSystemComponent->CreatePrefab({ wheelEntity }, {}, WheelPrefabMockFilePath);
  28. const TemplateId wheelTemplateId = wheelIsolatedInstance->GetTemplateId();
  29. PrefabDom& wheelTemplateDom = m_prefabSystemComponent->FindTemplateDom(wheelTemplateId);
  30. AZStd::vector<EntityAlias> wheelTemplateEntityAliases = wheelIsolatedInstance->GetEntityAliases();
  31. // Validate that the wheel template has the same entities(1) as the instance it was created from.
  32. ASSERT_EQ(wheelTemplateEntityAliases.size(), 1);
  33. PrefabTestDomUtils::ValidatePrefabDomEntities(wheelTemplateEntityAliases, wheelTemplateDom);
  34. // Create an axle with 0 entities and 2 wheel instances.
  35. AZStd::unique_ptr<Instance> wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId);
  36. AZStd::unique_ptr<Instance> wheel2UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId);
  37. AZStd::unique_ptr<Instance> axleInstance = m_prefabSystemComponent->CreatePrefab({},
  38. MakeInstanceList(AZStd::move(wheel1UnderAxle), AZStd::move(wheel2UnderAxle)), AxlePrefabMockFilePath);
  39. const TemplateId axleTemplateId = axleInstance->GetTemplateId();
  40. const AZStd::vector<InstanceAlias> wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId);
  41. PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId);
  42. // Create a car with 0 entities, 2 axle instances and 1 wheel instance.
  43. AZStd::unique_ptr<Instance> axle1UnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId);
  44. AZStd::unique_ptr<Instance> axle2UnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId);
  45. AZStd::unique_ptr<Instance> spareWheelUnderCar = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId);
  46. AZStd::unique_ptr<Instance> carInstance = m_prefabSystemComponent->CreatePrefab({},
  47. MakeInstanceList(AZStd::move(axle1UnderCar), AZStd::move(axle2UnderCar), AZStd::move(spareWheelUnderCar)), CarPrefabMockFilePath);
  48. const TemplateId carTemplateId = carInstance->GetTemplateId();
  49. const AZStd::vector<InstanceAlias> axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId);
  50. const AZStd::vector<InstanceAlias> wheelInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(wheelTemplateId);
  51. PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId);
  52. // Add another entity to a wheel instance and use it to update the wheel template.
  53. wheelIsolatedInstance->AddEntity(*CreateEntity("WheelEntity2"));
  54. PrefabDom updatedWheelInstance;
  55. ASSERT_TRUE(PrefabDomUtils::StoreInstanceInPrefabDom(*wheelIsolatedInstance, updatedWheelInstance));
  56. m_prefabSystemComponent->UpdatePrefabTemplate(wheelTemplateId, updatedWheelInstance);
  57. m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
  58. // Validate that the wheel template has the same entities(2) as the updated instance.
  59. wheelTemplateEntityAliases = wheelIsolatedInstance->GetEntityAliases();
  60. ASSERT_EQ(wheelTemplateEntityAliases.size(), 2);
  61. PrefabTestDomUtils::ValidatePrefabDomEntities(wheelTemplateEntityAliases, wheelTemplateDom);
  62. // Validate that the wheels under axle are updated with 2 entities
  63. PrefabTestDomUtils::ValidatePrefabDomInstances(wheelInstanceAliasesUnderAxle, axleTemplateDom, wheelTemplateDom);
  64. // Validate that the wheels of axles under the car have 2 entities
  65. PrefabTestDomUtils::ValidatePrefabDomInstances(axleInstanceAliasesUnderCar, carTemplateDom, axleTemplateDom);
  66. // Validate that the wheel under the car has 2 entities
  67. PrefabTestDomUtils::ValidatePrefabDomInstances(wheelInstanceAliasesUnderCar, carTemplateDom, wheelTemplateDom);
  68. }
  69. TEST_F(PrefabUpdateTemplateTest, UpdatePrefabTemplate_AddInstance_AllDependentTemplatesUpdated)
  70. {
  71. // Create a single entity wheel instance and create a template out of it.
  72. AZ::Entity* wheelEntity = CreateEntity("WheelEntity1");
  73. AddRequiredEditorComponents({ wheelEntity->GetId() });
  74. AZStd::unique_ptr<Instance> wheelIsolatedInstance = m_prefabSystemComponent->CreatePrefab({ wheelEntity },
  75. {}, WheelPrefabMockFilePath);
  76. const TemplateId wheelTemplateId = wheelIsolatedInstance->GetTemplateId();
  77. PrefabDom& wheelTemplateDom = m_prefabSystemComponent->FindTemplateDom(wheelTemplateId);
  78. // Create an axle with 0 entities and 1 wheel instance.
  79. AZStd::unique_ptr<Instance> wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId);
  80. AZStd::unique_ptr<Instance> axleInstance = m_prefabSystemComponent->CreatePrefab({},
  81. MakeInstanceList(AZStd::move(wheel1UnderAxle)), AxlePrefabMockFilePath);
  82. const TemplateId axleTemplateId = axleInstance->GetTemplateId();
  83. PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId);
  84. AZStd::vector<InstanceAlias> wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId);
  85. // Validate that there is only 1 wheel instance under axle.
  86. ASSERT_EQ(wheelInstanceAliasesUnderAxle.size(), 1);
  87. // Create a car with 0 entities and 2 axle instances.
  88. AZStd::unique_ptr<Instance> axle1UnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId);
  89. AZStd::unique_ptr<Instance> axle2UnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId);
  90. AZStd::unique_ptr<Instance> carInstance = m_prefabSystemComponent->CreatePrefab({},
  91. MakeInstanceList(AZStd::move(axle1UnderCar), AZStd::move(axle2UnderCar)), CarPrefabMockFilePath);
  92. const TemplateId carTemplateId = carInstance->GetTemplateId();
  93. const AZStd::vector<InstanceAlias> axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId);
  94. PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId);
  95. // Add another Wheel instance to Axle instance and use it to update the Axle template.
  96. AZStd::unique_ptr<Instance> wheel2UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId);
  97. axleInstance->AddInstance(AZStd::move(wheel2UnderAxle));
  98. PrefabDom updatedAxleInstanceDom;
  99. ASSERT_TRUE(PrefabDomUtils::StoreInstanceInPrefabDom(*axleInstance, updatedAxleInstanceDom));
  100. m_prefabSystemComponent->UpdatePrefabTemplate(axleTemplateId, updatedAxleInstanceDom);
  101. m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
  102. // Validate that there are 2 wheel instances under axle
  103. wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId);
  104. ASSERT_EQ(wheelInstanceAliasesUnderAxle.size(), 2);
  105. // Validate that the wheels under the axle have the same DOM as the wheel template.
  106. PrefabTestDomUtils::ValidatePrefabDomInstances(wheelInstanceAliasesUnderAxle, axleTemplateDom, wheelTemplateDom, false);
  107. // Validate that the axles under the car have the same DOM as the axle template.
  108. PrefabTestDomUtils::ValidatePrefabDomInstances(axleInstanceAliasesUnderCar, carTemplateDom, axleTemplateDom);
  109. }
  110. TEST_F(PrefabUpdateTemplateTest, UpdatePrefabTemplate_AddComponent_AllDependentTemplatesUpdated)
  111. {
  112. // Create a single entity wheel instance and create a template out of it.
  113. AZ::Entity* wheelEntity = CreateEntity("WheelEntity1", false);
  114. AZStd::unique_ptr<Instance> wheelIsolatedInstance = m_prefabSystemComponent->CreatePrefab({ wheelEntity },
  115. {}, WheelPrefabMockFilePath);
  116. const TemplateId wheelTemplateId = wheelIsolatedInstance->GetTemplateId();
  117. PrefabDom& wheelTemplateDom = m_prefabSystemComponent->FindTemplateDom(wheelTemplateId);
  118. AZStd::vector<EntityAlias> wheelTemplateEntityAliases = wheelIsolatedInstance->GetEntityAliases();
  119. // Validate that the wheel template has the same entities(1) as the instance it was created from.
  120. ASSERT_EQ(wheelTemplateEntityAliases.size(), 1);
  121. // Validate that the wheel entity doesn't have any components under it.
  122. EntityAlias entityAlias = wheelTemplateEntityAliases.front();
  123. PrefabDomValue* wheelEntityComponents =
  124. PrefabTestDomUtils::GetPrefabDomComponentsPath(entityAlias).Get(wheelTemplateDom);
  125. ASSERT_TRUE(wheelEntityComponents->IsArray() && wheelEntityComponents->Size() == 0);
  126. // Create an axle with 0 entities and 1 wheel instance.
  127. AZStd::unique_ptr<Instance> wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId);
  128. AZStd::unique_ptr<Instance> axleInstance = m_prefabSystemComponent->CreatePrefab({},
  129. MakeInstanceList(AZStd::move(wheel1UnderAxle)), AxlePrefabMockFilePath);
  130. const TemplateId axleTemplateId = axleInstance->GetTemplateId();
  131. PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId);
  132. const AZStd::vector<InstanceAlias> wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId);
  133. // Create a car with 0 entities and 1 axle instance.
  134. AZStd::unique_ptr<Instance> axleUnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId);
  135. AZStd::unique_ptr<Instance> carInstance = m_prefabSystemComponent->CreatePrefab({},
  136. MakeInstanceList(AZStd::move(axleUnderCar)), CarPrefabMockFilePath);
  137. const TemplateId carTemplateId = carInstance->GetTemplateId();
  138. const AZStd::vector<InstanceAlias> axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId);
  139. PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId);
  140. // Add a component to Wheel instance and use it to update the wheel template.
  141. PrefabTestComponent* prefabTestComponent = aznew PrefabTestComponent(true);
  142. // cache the RTTI name of the prefab test component, because the component will be deleted during the next few lines.
  143. AZStd::string prefabTestComponentRTTIName = prefabTestComponent->RTTI_GetTypeName();
  144. wheelEntity->AddComponent(prefabTestComponent);
  145. auto expectedComponentId = prefabTestComponent->GetId();
  146. PrefabDom updatedWheelInstanceDom;
  147. ASSERT_TRUE(PrefabDomUtils::StoreInstanceInPrefabDom(*wheelIsolatedInstance, updatedWheelInstanceDom));
  148. m_prefabSystemComponent->UpdatePrefabTemplate(wheelTemplateId, updatedWheelInstanceDom);
  149. m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
  150. // The above call destroys and recreates Entity and component instances, so pointers into
  151. // entities and components are no longer valid.
  152. prefabTestComponent = nullptr;
  153. // Validate that the wheel entity does have a component under it.
  154. wheelEntityComponents = PrefabTestDomUtils::GetPrefabDomComponentsPath(entityAlias).Get(wheelTemplateDom);
  155. ASSERT_TRUE(wheelEntityComponents != nullptr && wheelEntityComponents->IsObject());
  156. EXPECT_EQ(wheelEntityComponents->MemberCount(), 1);
  157. // Extract the component id of the entity in wheel template and verify that it matches with the component id of the wheel instance.
  158. PrefabTestDomUtils::ValidateComponentsDomHasId(*wheelEntityComponents, prefabTestComponentRTTIName.c_str(), expectedComponentId);
  159. // Validate that the wheels under the axle have the same DOM as the wheel template.
  160. PrefabTestDomUtils::ValidatePrefabDomInstances(wheelInstanceAliasesUnderAxle, axleTemplateDom, wheelTemplateDom);
  161. // Validate that the axles under the car have the same DOM as the axle template.
  162. PrefabTestDomUtils::ValidatePrefabDomInstances(axleInstanceAliasesUnderCar, carTemplateDom, axleTemplateDom);
  163. }
  164. TEST_F(PrefabUpdateTemplateTest, UpdatePrefabTemplate_DetachEntity_AllDependentTemplatesUpdated)
  165. {
  166. // Create wheel instance with 2 entities and create a template out of it.
  167. AZ::Entity* wheelEntity1 = CreateEntity("WheelEntity1");
  168. AZ::Entity* wheelEntity2 = CreateEntity("WheelEntity2");
  169. AZStd::unique_ptr<Instance> wheelIsolatedInstance = m_prefabSystemComponent->CreatePrefab({ wheelEntity1, wheelEntity2 },
  170. {}, WheelPrefabMockFilePath);
  171. const TemplateId wheelTemplateId = wheelIsolatedInstance->GetTemplateId();
  172. PrefabDom& wheelTemplateDom = m_prefabSystemComponent->FindTemplateDom(wheelTemplateId);
  173. // Validate that the wheel template has the same entities(2) as the instance it was created from.
  174. AZStd::vector<EntityAlias> wheelTemplateEntityAliases = wheelIsolatedInstance->GetEntityAliases();
  175. ASSERT_EQ(wheelTemplateEntityAliases.size(), 2);
  176. // Create an axle with 0 entities and 1 wheel instance.
  177. AZStd::unique_ptr<Instance> wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId);
  178. AZStd::unique_ptr<Instance> axleInstance = m_prefabSystemComponent->CreatePrefab({},
  179. MakeInstanceList(AZStd::move(wheel1UnderAxle)), AxlePrefabMockFilePath);
  180. const TemplateId axleTemplateId = axleInstance->GetTemplateId();
  181. PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId);
  182. const AZStd::vector<InstanceAlias> wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId);
  183. // Create a car with 0 entities and 1 axle instance.
  184. AZStd::unique_ptr<Instance> axleUnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId);
  185. AZStd::unique_ptr<Instance> carInstance = m_prefabSystemComponent->CreatePrefab({},
  186. MakeInstanceList(AZStd::move(axleUnderCar)), CarPrefabMockFilePath);
  187. const TemplateId carTemplateId = carInstance->GetTemplateId();
  188. const AZStd::vector<InstanceAlias> axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId);
  189. PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId);
  190. // Detach the first entity from the Wheel instance and use it to update the wheel template.
  191. AZStd::unique_ptr<AZ::Entity> detachedEntity = wheelIsolatedInstance->DetachEntity(wheelEntity1->GetId());
  192. ASSERT_TRUE(detachedEntity);
  193. PrefabDom updatedWheelInstanceDom;
  194. ASSERT_TRUE(PrefabDomUtils::StoreInstanceInPrefabDom(*wheelIsolatedInstance, updatedWheelInstanceDom));
  195. m_prefabSystemComponent->UpdatePrefabTemplate(wheelTemplateId, updatedWheelInstanceDom);
  196. m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
  197. // Validate that the wheel template only has 1 entity now.
  198. wheelTemplateEntityAliases = wheelIsolatedInstance->GetEntityAliases();
  199. ASSERT_EQ(wheelTemplateEntityAliases.size(), 1);
  200. PrefabTestDomUtils::ValidatePrefabDomEntities(wheelTemplateEntityAliases, wheelTemplateDom);
  201. // Validate that the wheels under the axle have the same DOM as the wheel template.
  202. PrefabTestDomUtils::ValidatePrefabDomInstances(wheelInstanceAliasesUnderAxle, axleTemplateDom, wheelTemplateDom);
  203. // Validate that the axles under the car have the same DOM as the axle template.
  204. PrefabTestDomUtils::ValidatePrefabDomInstances(axleInstanceAliasesUnderCar, carTemplateDom, axleTemplateDom);
  205. }
  206. TEST_F(PrefabUpdateTemplateTest, UpdatePrefabTemplate_DetachNestedInstance_AllDependentTemplatesUpdated)
  207. {
  208. // Create a single entity wheel instance and create a template out of it.
  209. AZ::Entity* wheelEntity = CreateEntity("WheelEntity1");
  210. AddRequiredEditorComponents({ wheelEntity->GetId() });
  211. AZStd::unique_ptr<Instance> wheelIsolatedInstance = m_prefabSystemComponent->CreatePrefab({ wheelEntity },
  212. {}, WheelPrefabMockFilePath);
  213. const TemplateId wheelTemplateId = wheelIsolatedInstance->GetTemplateId();
  214. PrefabDom& wheelTemplateDom = m_prefabSystemComponent->FindTemplateDom(wheelTemplateId);
  215. // Create an axle with 0 entities and 2 wheel instances.
  216. AZStd::unique_ptr<Instance> wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId);
  217. AZStd::unique_ptr<Instance> wheel2UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId);
  218. AZStd::unique_ptr<Instance> axleInstance = m_prefabSystemComponent->CreatePrefab({},
  219. MakeInstanceList(AZStd::move(wheel1UnderAxle), AZStd::move(wheel2UnderAxle) ),
  220. AxlePrefabMockFilePath);
  221. const TemplateId axleTemplateId = axleInstance->GetTemplateId();
  222. PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId);
  223. AZStd::vector<InstanceAlias> wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId);
  224. // Validate that there are 2 wheel instances under axle.
  225. ASSERT_EQ(wheelInstanceAliasesUnderAxle.size(), 2);
  226. // Create a car with 0 entities and 1 axle instance.
  227. AZStd::unique_ptr<Instance> axle1UnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId);
  228. AZStd::unique_ptr<Instance> carInstance = m_prefabSystemComponent->CreatePrefab({},
  229. MakeInstanceList(AZStd::move(axle1UnderCar)), CarPrefabMockFilePath);
  230. const TemplateId carTemplateId = carInstance->GetTemplateId();
  231. const AZStd::vector<InstanceAlias> axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId);
  232. PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId);
  233. // Detach second wheel instance from Axle instance and use it to update the Axle template.
  234. InstanceAlias aliasOfWheelInstanceToRetain = wheelInstanceAliasesUnderAxle.front();
  235. AZStd::unique_ptr<Instance> detachedInstance = axleInstance->DetachNestedInstance(wheelInstanceAliasesUnderAxle.back());
  236. ASSERT_TRUE(detachedInstance);
  237. m_prefabSystemComponent->RemoveLink(detachedInstance->GetLinkId());
  238. PrefabDom updatedAxleInstanceDom;
  239. ASSERT_TRUE(PrefabDomUtils::StoreInstanceInPrefabDom(*axleInstance, updatedAxleInstanceDom));
  240. m_prefabSystemComponent->UpdatePrefabTemplate(axleTemplateId, updatedAxleInstanceDom);
  241. m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
  242. // Validate that there is only 1 wheel instances under axle
  243. wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId);
  244. ASSERT_EQ(wheelInstanceAliasesUnderAxle.size(), 1);
  245. EXPECT_EQ(wheelInstanceAliasesUnderAxle.front(), aliasOfWheelInstanceToRetain);
  246. // Validate that the wheels under the axle have the same DOM as the wheel template.
  247. PrefabTestDomUtils::ValidatePrefabDomInstances(wheelInstanceAliasesUnderAxle, axleTemplateDom, wheelTemplateDom, false);
  248. // Validate that the axles under the car have the same DOM as the axle template.
  249. PrefabTestDomUtils::ValidatePrefabDomInstances(axleInstanceAliasesUnderCar, carTemplateDom, axleTemplateDom);
  250. }
  251. TEST_F(PrefabUpdateTemplateTest, UpdatePrefabTemplate_RemoveComponent_AllDependentTemplatesUpdated)
  252. {
  253. // Create a single entity wheel instance with a PrefabTestComponent and create a template out of it.
  254. AZ::Entity* wheelEntity = CreateEntity("WheelEntity1", false);
  255. PrefabTestComponent* prefabTestComponent = aznew PrefabTestComponent(true);
  256. wheelEntity->AddComponent(prefabTestComponent);
  257. AZStd::unique_ptr<Instance> wheelIsolatedInstance = m_prefabSystemComponent->CreatePrefab({ wheelEntity },
  258. {}, WheelPrefabMockFilePath);
  259. const TemplateId wheelTemplateId = wheelIsolatedInstance->GetTemplateId();
  260. PrefabDom& wheelTemplateDom = m_prefabSystemComponent->FindTemplateDom(wheelTemplateId);
  261. AZStd::vector<EntityAlias> wheelTemplateEntityAliases = wheelIsolatedInstance->GetEntityAliases();
  262. // Validate that the wheel template has the same entities(1) as the instance it was created from.
  263. ASSERT_EQ(wheelTemplateEntityAliases.size(), 1);
  264. // Validate that the wheel entity has 1 component under it.
  265. AZStd::string entityAlias = wheelTemplateEntityAliases.front();
  266. PrefabDomValue* wheelEntityComponents =
  267. PrefabTestDomUtils::GetPrefabDomComponentsPath(entityAlias).Get(wheelTemplateDom);
  268. ASSERT_TRUE(wheelEntityComponents != nullptr && wheelEntityComponents->IsObject());
  269. EXPECT_EQ(wheelEntityComponents->MemberCount(), 1);
  270. // Extract the component id of the entity in wheel template and verify that it matches with the component id of the wheel instance.
  271. PrefabTestDomUtils::ValidateComponentsDomHasId(
  272. *wheelEntityComponents, prefabTestComponent->RTTI_GetTypeName(), prefabTestComponent->GetId());
  273. // Create an axle with 0 entities and 1 wheel instance.
  274. AZStd::unique_ptr<Instance> wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId);
  275. AZStd::unique_ptr<Instance> axleInstance = m_prefabSystemComponent->CreatePrefab({},
  276. MakeInstanceList(AZStd::move(wheel1UnderAxle)), AxlePrefabMockFilePath);
  277. const TemplateId axleTemplateId = axleInstance->GetTemplateId();
  278. PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId);
  279. const AZStd::vector<InstanceAlias> wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId);
  280. // Create a car with 0 entities and 1 axle instance.
  281. AZStd::unique_ptr<Instance> axleUnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId);
  282. AZStd::unique_ptr<Instance> carInstance = m_prefabSystemComponent->CreatePrefab({},
  283. MakeInstanceList(AZStd::move(axleUnderCar)), CarPrefabMockFilePath);
  284. const TemplateId carTemplateId = carInstance->GetTemplateId();
  285. const AZStd::vector<InstanceAlias> axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId);
  286. PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId);
  287. // Remove the component from Wheel instance and use it to update the wheel template.
  288. wheelEntity->RemoveComponent(prefabTestComponent);
  289. PrefabDom updatedWheelInstanceDom;
  290. ASSERT_TRUE(PrefabDomUtils::StoreInstanceInPrefabDom(*wheelIsolatedInstance, updatedWheelInstanceDom));
  291. m_prefabSystemComponent->UpdatePrefabTemplate(wheelTemplateId, updatedWheelInstanceDom);
  292. m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
  293. // Validate that the wheel entity does not have a component under it.
  294. wheelEntityComponents = PrefabTestDomUtils::GetPrefabDomComponentsPath(entityAlias).Get(wheelTemplateDom);
  295. ASSERT_TRUE(wheelEntityComponents->IsArray() && wheelEntityComponents->Size() == 0);
  296. // Validate that the wheels under the axle have the same DOM as the wheel template.
  297. PrefabTestDomUtils::ValidatePrefabDomInstances(wheelInstanceAliasesUnderAxle, axleTemplateDom, wheelTemplateDom);
  298. // Validate that the axles under the car have the same DOM as the axle template.
  299. PrefabTestDomUtils::ValidatePrefabDomInstances(axleInstanceAliasesUnderCar, carTemplateDom, axleTemplateDom);
  300. delete prefabTestComponent;
  301. }
  302. TEST_F(PrefabUpdateTemplateTest, UpdatePrefabTemplate_ChangeComponentProperty_AllDependentTemplatesUpdated)
  303. {
  304. // Create a single entity wheel instance with a PrefabTestComponent and create a template out of it.
  305. AZ::Entity* wheelEntity = CreateEntity("WheelEntity1", false);
  306. PrefabTestComponent* prefabTestComponent = aznew PrefabTestComponent(true);
  307. wheelEntity->AddComponent(prefabTestComponent);
  308. AZStd::unique_ptr<Instance> wheelIsolatedInstance = m_prefabSystemComponent->CreatePrefab({ wheelEntity },
  309. {}, WheelPrefabMockFilePath);
  310. const TemplateId wheelTemplateId = wheelIsolatedInstance->GetTemplateId();
  311. PrefabDom& wheelTemplateDom = m_prefabSystemComponent->FindTemplateDom(wheelTemplateId);
  312. AZStd::vector<EntityAlias> wheelTemplateEntityAliases = wheelIsolatedInstance->GetEntityAliases();
  313. // Validate that the wheel template has the same entities(1) as the instance it was created from.
  314. ASSERT_EQ(wheelTemplateEntityAliases.size(), 1);
  315. // Validate that the wheel entity has 1 component under it.
  316. AZStd::string entityAlias = wheelTemplateEntityAliases.front();
  317. PrefabDomValue* wheelEntityComponents =
  318. PrefabTestDomUtils::GetPrefabDomComponentsPath(entityAlias).Get(wheelTemplateDom);
  319. ASSERT_TRUE(wheelEntityComponents != nullptr && wheelEntityComponents->IsObject());
  320. EXPECT_EQ(wheelEntityComponents->MemberCount(), 1);
  321. // Extract the component id of the entity in wheel template and verify that it matches with the component id of the wheel instance.
  322. PrefabTestDomUtils::ValidateComponentsDomHasId(
  323. *wheelEntityComponents, prefabTestComponent->RTTI_GetTypeName(), prefabTestComponent->GetId());
  324. // Create an axle with 0 entities and 1 wheel instance.
  325. AZStd::unique_ptr<Instance> wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId);
  326. AZStd::unique_ptr<Instance> axleInstance = m_prefabSystemComponent->CreatePrefab({},
  327. MakeInstanceList(AZStd::move(wheel1UnderAxle)), AxlePrefabMockFilePath);
  328. const TemplateId axleTemplateId = axleInstance->GetTemplateId();
  329. PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId);
  330. const AZStd::vector<InstanceAlias> wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId);
  331. // Create a car with 0 entities and 1 axle instance.
  332. AZStd::unique_ptr<Instance> axleUnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId);
  333. AZStd::unique_ptr<Instance> carInstance = m_prefabSystemComponent->CreatePrefab({},
  334. MakeInstanceList(AZStd::move(axleUnderCar)), CarPrefabMockFilePath);
  335. const TemplateId carTemplateId = carInstance->GetTemplateId();
  336. const AZStd::vector<InstanceAlias> axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId);
  337. PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId);
  338. // Change the bool property of the component from Wheel instance and use it to update the wheel template.
  339. prefabTestComponent->m_boolProperty = false;
  340. PrefabDom updatedWheelInstanceDom;
  341. ASSERT_TRUE(PrefabDomUtils::StoreInstanceInPrefabDom(*wheelIsolatedInstance, updatedWheelInstanceDom));
  342. m_prefabSystemComponent->UpdatePrefabTemplate(wheelTemplateId, updatedWheelInstanceDom);
  343. m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
  344. // Validate that the BoolProperty of the prefabTestComponent in the wheel template DOM is set to false.
  345. wheelEntityComponents = PrefabTestDomUtils::GetPrefabDomComponentsPath(entityAlias).Get(wheelTemplateDom);
  346. ASSERT_TRUE(wheelEntityComponents != nullptr && wheelEntityComponents->IsObject());
  347. EXPECT_EQ(wheelEntityComponents->MemberCount(), 1);
  348. PrefabDomValueReference wheelEntityComponentBoolPropertyValue =
  349. PrefabDomUtils::FindPrefabDomValue(wheelEntityComponents->MemberBegin()->value, PrefabTestDomUtils::BoolPropertyName);
  350. ASSERT_TRUE(wheelEntityComponentBoolPropertyValue.has_value() && wheelEntityComponentBoolPropertyValue->get() == false);
  351. // Validate that the wheels under the axle have the same DOM as the wheel template.
  352. PrefabTestDomUtils::ValidatePrefabDomInstances(wheelInstanceAliasesUnderAxle, axleTemplateDom, wheelTemplateDom);
  353. // Validate that the axles under the car have the same DOM as the axle template.
  354. PrefabTestDomUtils::ValidatePrefabDomInstances(axleInstanceAliasesUnderCar, carTemplateDom, axleTemplateDom);
  355. }
  356. }