PrefabEntityAliasTests.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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 <Prefab/PrefabTestDomUtils.h>
  9. #include <Prefab/PrefabTestComponent.h>
  10. #include <Prefab/PrefabTestFixture.h>
  11. namespace UnitTest
  12. {
  13. using PrefabEntityAliasTests = PrefabTestFixture;
  14. TEST_F(PrefabEntityAliasTests, PrefabEntityAlias_ReferenceEntityWithinSameInstance_ReferencePersists)
  15. {
  16. // Make a new entity with a test component
  17. AZ::Entity* newEntity = CreateEntity("New Entity", false);
  18. PrefabTestComponent* newComponent = newEntity->CreateComponent<PrefabTestComponent>();
  19. ASSERT_TRUE(newComponent);
  20. // Generate a second entity that will be referenced by the first
  21. AZ::Entity* referencedEntity = CreateEntity("Referenced Entity");
  22. newComponent->m_entityIdProperty = referencedEntity->GetId();
  23. // Place both entities in the same prefab
  24. AZStd::unique_ptr<Instance> newInstance =
  25. m_prefabSystemComponent->CreatePrefab({ newEntity, referencedEntity }, {}, "test/path");
  26. ASSERT_TRUE(newInstance);
  27. // Grab the alias of both entities so they can be found in a new instantiation
  28. EntityAliasOptionalReference newEntityAliasRef = newInstance->GetEntityAlias(newEntity->GetId());
  29. ASSERT_TRUE(newEntityAliasRef);
  30. EntityAliasOptionalReference referencedEntityAliasRef = newInstance->GetEntityAlias(referencedEntity->GetId());
  31. ASSERT_TRUE(referencedEntityAliasRef);
  32. EntityAlias newEntityAlias = newEntityAliasRef.value();
  33. EntityAlias referencedEntityAlias = referencedEntityAliasRef.value();
  34. // A new instance should maintain the entity reference while also having unique entity ids
  35. AZStd::unique_ptr<Instance> secondInstance =
  36. m_prefabSystemComponent->InstantiatePrefab(newInstance->GetTemplateId());
  37. bool found = false;
  38. secondInstance->GetConstEntities([&](const AZ::Entity& entity)
  39. {
  40. if (entity.GetId() == secondInstance->GetEntityId(newEntityAlias))
  41. {
  42. PrefabTestComponent* secondComponent = entity.FindComponent<PrefabTestComponent>();
  43. EXPECT_NE(nullptr, secondComponent);
  44. if (secondComponent)
  45. {
  46. // Validate that the entity reference is preserved in the second instance
  47. EXPECT_TRUE(secondComponent->m_entityIdProperty.IsValid());
  48. EXPECT_EQ(secondComponent->m_entityIdProperty, secondInstance->GetEntityId(referencedEntityAlias));
  49. }
  50. found = true;
  51. }
  52. return true;
  53. });
  54. EXPECT_TRUE(found);
  55. }
  56. TEST_F(PrefabEntityAliasTests, DISABLED_PrefabEntityAlias_ReferenceNotInSameHierarchy_ReferenceGoesToNull)
  57. {
  58. // Make a new entity with a test component
  59. AZ::Entity* newEntity = CreateEntity("New Entity", false);
  60. PrefabTestComponent* newComponent = newEntity->CreateComponent<PrefabTestComponent>();
  61. ASSERT_TRUE(newComponent);
  62. // Generate a second entity that will be referenced by the first
  63. // however we won't add both to the same prefab hierarchy
  64. AZ::Entity* referencedEntity = CreateEntity("Referenced Entity");
  65. newComponent->m_entityIdProperty = referencedEntity->GetId();
  66. AZStd::unique_ptr<Instance> unrelatedInstance =
  67. m_prefabSystemComponent->CreatePrefab({ referencedEntity }, {}, "test/path/0");
  68. AZStd::unique_ptr<Instance> firstInstance =
  69. m_prefabSystemComponent->CreatePrefab({ newEntity }, {}, "test/path/1");
  70. ASSERT_TRUE(firstInstance);
  71. // Grab the alias of newEntity so it can be found in a new instantiation
  72. EntityAliasOptionalReference newEntityAliasRef = firstInstance->GetEntityAlias(newEntity->GetId());
  73. ASSERT_TRUE(newEntityAliasRef);
  74. EntityAlias newEntityAlias = newEntityAliasRef.value();
  75. // On instantiation the referenced entity should be invalid
  76. AZStd::unique_ptr<Instance> secondInstance =
  77. m_prefabSystemComponent->InstantiatePrefab(firstInstance->GetTemplateId());
  78. size_t count = 0;
  79. secondInstance->GetConstEntities([&](const AZ::Entity& entity)
  80. {
  81. count++;
  82. PrefabTestComponent* secondComponent = entity.FindComponent<PrefabTestComponent>();
  83. EXPECT_NE(nullptr, secondComponent);
  84. if (secondComponent)
  85. {
  86. EXPECT_FALSE(secondComponent->m_entityIdProperty.IsValid());
  87. }
  88. return true;
  89. });
  90. EXPECT_EQ(1, count);
  91. }
  92. TEST_F(PrefabEntityAliasTests, PrefabEntityAlias_ReferenceEntityFoundInNestedInstance_ReferencePersists)
  93. {
  94. // Make a new entity with a test component
  95. AZ::Entity* newEntity = CreateEntity("New Entity", false);
  96. PrefabTestComponent* newComponent = newEntity->CreateComponent<PrefabTestComponent>();
  97. ASSERT_TRUE(newComponent);
  98. // Generate a second entity that will be referenced by the first
  99. AZ::Entity* referencedEntity = CreateEntity("Referenced Entity");
  100. newComponent->m_entityIdProperty = referencedEntity->GetId();
  101. // Build out a prefab holding the referenced entity
  102. AZStd::unique_ptr<Instance> nestedInstance =
  103. m_prefabSystemComponent->CreatePrefab({ referencedEntity }, {}, "Test/Path/0");
  104. // Grab the alias of the nested instance
  105. EntityAliasOptionalReference referencedEntityAliasRef =
  106. nestedInstance->GetEntityAlias(referencedEntity->GetId());
  107. ASSERT_TRUE(referencedEntityAliasRef);
  108. EntityAlias referencedEntityAlias = referencedEntityAliasRef.value();
  109. TemplateId nestedTemplateId = nestedInstance->GetTemplateId();
  110. // Create our root instance and nest our first instance under it
  111. AZStd::unique_ptr<Instance> rootInstance =
  112. m_prefabSystemComponent->CreatePrefab({ newEntity },
  113. PrefabTestUtils::MakeInstanceList(AZStd::move(nestedInstance)), "Test/Path/1");
  114. // Acquire the alias name of our entity so we can look it up in future instances
  115. EntityAliasOptionalReference newEntityAliasRef =
  116. rootInstance->GetEntityAlias(newEntity->GetId());
  117. ASSERT_TRUE(newEntityAliasRef);
  118. EntityAlias newEntityAlias = newEntityAliasRef.value();
  119. // Acquire the nested instance alias so we can look it up in future instances
  120. AZStd::vector<InstanceAlias> nestedInstanceAliases = rootInstance->GetNestedInstanceAliases(nestedTemplateId);
  121. ASSERT_EQ(nestedInstanceAliases.size(), 1);
  122. InstanceAlias nestedAlias = nestedInstanceAliases[0];
  123. // Make a new instance of root
  124. // Entity references should be preserved among its unique entities
  125. AZStd::unique_ptr<Instance> secondRootInstance =
  126. m_prefabSystemComponent->InstantiatePrefab(rootInstance->GetTemplateId());
  127. ASSERT_TRUE(secondRootInstance);
  128. InstanceOptionalReference secondNestedInstance = secondRootInstance->FindNestedInstance(nestedAlias);
  129. ASSERT_TRUE(secondNestedInstance);
  130. AZ::EntityId secondReferencedEntityId = secondNestedInstance->get().GetEntityId(referencedEntityAlias);
  131. size_t count = 0;
  132. secondRootInstance->GetConstEntities([&](const AZ::Entity& entity)
  133. {
  134. count++;
  135. PrefabTestComponent* secondComponent = entity.FindComponent<PrefabTestComponent>();
  136. EXPECT_NE(nullptr, secondComponent);
  137. if (secondComponent)
  138. {
  139. EXPECT_TRUE(secondComponent->m_entityIdProperty.IsValid());
  140. EXPECT_EQ(secondComponent->m_entityIdProperty, secondReferencedEntityId);
  141. }
  142. return true;
  143. });
  144. EXPECT_EQ(1, count);
  145. }
  146. TEST_F(PrefabEntityAliasTests, PrefabEntityAlias_ReferenceEntityFoundInParentInstance_ReferencePersists)
  147. {
  148. // Make a new entity with a test component
  149. AZ::Entity* newEntity = CreateEntity("New Entity", false);
  150. PrefabTestComponent* newComponent = newEntity->CreateComponent<PrefabTestComponent>();
  151. ASSERT_TRUE(newComponent);
  152. // Generate a second entity that will be referenced by the first
  153. AZ::Entity* referencedEntity = CreateEntity("Referenced Entity");
  154. // Make our first instance to be nested under the prefab containing the entity we reference
  155. AZStd::unique_ptr<Instance> nestedInstance =
  156. m_prefabSystemComponent->CreatePrefab({ newEntity }, {}, "Test/Path/0");
  157. // Save off the entity alias so we can find it in future instances
  158. EntityAliasOptionalReference newEntityAliasRef = nestedInstance->GetEntityAlias(newEntity->GetId());
  159. ASSERT_TRUE(newEntityAliasRef);
  160. EntityAlias entityAlias = newEntityAliasRef.value();
  161. TemplateId nestedTemplateId = nestedInstance->GetTemplateId();
  162. // Make our root instance which contains the entity being referenced
  163. AZStd::unique_ptr<Instance> rootInstance =
  164. m_prefabSystemComponent->CreatePrefab({ referencedEntity },
  165. PrefabTestUtils::MakeInstanceList(AZStd::move(nestedInstance)), "Test/Path/1");
  166. // Acquire the nested instance alias so we can look it up in future instances
  167. AZStd::vector<InstanceAlias> nestedInstanceAliases = rootInstance->GetNestedInstanceAliases(nestedTemplateId);
  168. ASSERT_EQ(nestedInstanceAliases.size(), 1);
  169. InstanceAlias nestedAlias = nestedInstanceAliases[0];
  170. // Save off the referenced entity alias
  171. EntityAliasOptionalReference referencedEntityAliasRef =
  172. rootInstance->GetEntityAlias(referencedEntity->GetId());
  173. ASSERT_TRUE(referencedEntityAliasRef);
  174. EntityAlias referencedEntityAlias = referencedEntityAliasRef.value();
  175. // Capture the before and after for setting the reference property
  176. PrefabDom entityDomBeforeUpdate;
  177. m_instanceToTemplateInterface->GenerateEntityDomBySerializing(entityDomBeforeUpdate, *newEntity);
  178. newComponent->m_entityIdProperty = referencedEntity->GetId();
  179. PrefabDom entityDomAfterUpdate;
  180. m_instanceToTemplateInterface->GenerateEntityDomBySerializing(entityDomAfterUpdate, *newEntity);
  181. PrefabDom patch;
  182. m_instanceToTemplateInterface->GeneratePatch(patch, entityDomBeforeUpdate, entityDomAfterUpdate);
  183. // Patch the nested prefab to reference an entity in its parent
  184. ASSERT_TRUE(m_instanceToTemplateInterface->PatchEntityInTemplate(patch, newEntity->GetId()));
  185. m_instanceUpdateExecutorInterface->AddTemplateInstancesToQueue(rootInstance->GetTemplateId());
  186. m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
  187. // Using the aliases we saved grab the updated entities so we can verify the entity reference is still preserved
  188. InstanceOptionalReference updatedNestedInstance = rootInstance->FindNestedInstance(nestedAlias);
  189. ASSERT_TRUE(updatedNestedInstance);
  190. AZ::EntityId updatedNewEntityId = updatedNestedInstance->get().GetEntityId(entityAlias);
  191. AZ::Entity* updatedNewEntity = nullptr;
  192. AZ::ComponentApplicationBus::BroadcastResult(updatedNewEntity,
  193. &AZ::ComponentApplicationBus::Events::FindEntity, updatedNewEntityId);
  194. ASSERT_TRUE(updatedNewEntity);
  195. PrefabTestComponent* updatedComponent = updatedNewEntity->FindComponent<PrefabTestComponent>();
  196. ASSERT_TRUE(updatedComponent);
  197. AZ::EntityId updatedReferencedEntityId = rootInstance->GetEntityId(referencedEntityAlias);
  198. EXPECT_TRUE(updatedComponent->m_entityIdProperty.IsValid());
  199. EXPECT_EQ(updatedComponent->m_entityIdProperty, updatedReferencedEntityId);
  200. }
  201. }