PrefabUndoEditEntityTests.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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/PrefabTestFixture.h>
  9. #include <AzToolsFramework/Entity/EditorEntityHelpers.h>
  10. #include <AzToolsFramework/Prefab/Undo/PrefabUndo.h>
  11. #include <AzToolsFramework/Prefab/Undo/PrefabUndoEntityOverrides.h>
  12. #include <Prefab/PrefabTestComponent.h>
  13. namespace UnitTest
  14. {
  15. using PrefabUndoEditEntityTests = PrefabTestFixture;
  16. TEST_F(PrefabUndoEditEntityTests, EditEntity)
  17. {
  18. const AZStd::string wheelEntityName = "Wheel";
  19. AZ::IO::Path engineRootPath;
  20. m_settingsRegistryInterface->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
  21. AZ::EntityId wheelEntityId = CreateEditorEntityUnderRoot(wheelEntityName);
  22. // Modify the transform component
  23. AZ::TransformBus::Event(wheelEntityId, &AZ::TransformInterface::SetWorldX, 10.0f);
  24. // Add a new comopnent
  25. AZ::Entity* wheelEntity = AzToolsFramework::GetEntityById(wheelEntityId);
  26. wheelEntity->Deactivate();
  27. wheelEntity->AddComponent(aznew PrefabTestComponent());
  28. wheelEntity->Activate();
  29. // Get after-state DOM value
  30. wheelEntity = AzToolsFramework::GetEntityById(wheelEntityId);
  31. EXPECT_TRUE(wheelEntity) << "Could not get entity object.";
  32. PrefabDom entityDomAfterEdit;
  33. m_instanceToTemplateInterface->GenerateEntityDomBySerializing(entityDomAfterEdit, *wheelEntity);
  34. EXPECT_TRUE(entityDomAfterEdit.IsObject()) << "Could not create after-state entity DOM.";
  35. // Get before-state DOM value
  36. AZStd::string entityAliasPath = m_instanceToTemplateInterface->GenerateEntityAliasPath(wheelEntityId);
  37. EXPECT_FALSE(entityAliasPath.empty());
  38. InstanceOptionalReference owningInstance = m_instanceEntityMapperInterface->FindOwningInstance(wheelEntityId);
  39. TemplateId templateId = owningInstance->get().GetTemplateId();
  40. EXPECT_TRUE(templateId != InvalidTemplateId);
  41. PrefabDom& templateDom = m_prefabSystemComponent->FindTemplateDom(templateId);
  42. PrefabDomValue* entityDomInTemplate = PrefabDomPath(entityAliasPath.c_str()).Get(templateDom);
  43. EXPECT_TRUE(entityDomInTemplate) << "Could not retrieve entity DOM from template.";
  44. // Create an undo node
  45. PrefabUndoEntityUpdate undoNode("Undo Editing Entity");
  46. undoNode.Capture(*entityDomInTemplate, entityDomAfterEdit, wheelEntityId);
  47. // Redo
  48. undoNode.Redo();
  49. PropagateAllTemplateChanges();
  50. // Note for the following code and all other code in this file,
  51. // PropagateAllTemplateChanges() may delete and re-create entities, it is not safe
  52. // to hold onto entity* pointers across this call. You must fetch them by ID again.
  53. wheelEntity = AzToolsFramework::GetEntityById(wheelEntityId);
  54. ASSERT_FLOAT_EQ(10.0f, wheelEntity->GetTransform()->GetWorldX());
  55. ASSERT_TRUE(wheelEntity->FindComponent<PrefabTestComponent>());
  56. // Undo
  57. undoNode.Undo();
  58. PropagateAllTemplateChanges();
  59. wheelEntity = AzToolsFramework::GetEntityById(wheelEntityId);
  60. ASSERT_FLOAT_EQ(0.0f, wheelEntity->GetTransform()->GetWorldX());
  61. ASSERT_FALSE(wheelEntity->FindComponent<PrefabTestComponent>());
  62. // Redo
  63. undoNode.Redo();
  64. PropagateAllTemplateChanges();
  65. wheelEntity = AzToolsFramework::GetEntityById(wheelEntityId);
  66. ASSERT_FLOAT_EQ(10.0f, wheelEntity->GetTransform()->GetWorldX());
  67. ASSERT_TRUE(wheelEntity->FindComponent<PrefabTestComponent>());
  68. }
  69. TEST_F(PrefabUndoEditEntityTests, EditEntityAsOverride)
  70. {
  71. PrefabOverridePublicInterface* overrideInterface = AZ::Interface<PrefabOverridePublicInterface>::Get();
  72. EXPECT_TRUE(overrideInterface) << "Could not get the override public interface.";
  73. const AZStd::string carPrefabName = "Car";
  74. const AZStd::string wheelEntityName = "Wheel";
  75. AZ::IO::Path engineRootPath;
  76. m_settingsRegistryInterface->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
  77. AZ::IO::Path carPrefabFilepath = engineRootPath / carPrefabName;
  78. AZ::EntityId wheelEntityId = CreateEditorEntityUnderRoot(wheelEntityName);
  79. AZ::EntityId carContainerId = CreateEditorPrefab(carPrefabFilepath, { wheelEntityId });
  80. EntityAlias wheelEntityAlias = FindEntityAliasInInstance(carContainerId, wheelEntityName);
  81. EXPECT_FALSE(wheelEntityAlias.empty());
  82. InstanceOptionalReference levelRootInstance = m_instanceEntityMapperInterface->FindOwningInstance(GetRootContainerEntityId());
  83. EXPECT_TRUE(levelRootInstance.has_value());
  84. InstanceOptionalReference carInstance = m_instanceEntityMapperInterface->FindOwningInstance(carContainerId);
  85. EXPECT_TRUE(carInstance.has_value());
  86. // Retrieve the wheel entity object and entity id after adding to instance
  87. EntityOptionalReference wheelEntityRef = carInstance->get().GetEntity(wheelEntityAlias);
  88. EXPECT_TRUE(wheelEntityRef.has_value());
  89. AZ::Entity* wheelEntity = &(wheelEntityRef->get());
  90. wheelEntityId = wheelEntity->GetId();
  91. // Modify the transform component as override
  92. AZ::TransformBus::Event(wheelEntityId, &AZ::TransformInterface::SetWorldX, 10.0f);
  93. // Add a new comopnent as override
  94. wheelEntity->Deactivate();
  95. wheelEntity->AddComponent(aznew PrefabTestComponent());
  96. wheelEntity->Activate();
  97. // Create an undo node and redo
  98. PrefabUndoEntityOverrides undoNode("Undo Editing Entity As Override");
  99. undoNode.CaptureAndRedo({ wheelEntity }, carInstance->get(), levelRootInstance->get());
  100. PropagateAllTemplateChanges();
  101. // Note for the following code and all other code in this file,
  102. // PropagateAllTemplateChanges() may delete and re-create entities, it is not safe
  103. // to hold onto entity* pointers across this call. You must fetch them by ID again.
  104. wheelEntity = AzToolsFramework::GetEntityById(wheelEntityId);
  105. ASSERT_TRUE(overrideInterface->AreOverridesPresent(wheelEntityId));
  106. ASSERT_FLOAT_EQ(10.0f, wheelEntity->GetTransform()->GetWorldX());
  107. ASSERT_TRUE(wheelEntity->FindComponent<PrefabTestComponent>());
  108. // Undo
  109. undoNode.Undo();
  110. PropagateAllTemplateChanges();
  111. wheelEntity = AzToolsFramework::GetEntityById(wheelEntityId);
  112. ASSERT_FALSE(overrideInterface->AreOverridesPresent(wheelEntityId));
  113. ASSERT_FLOAT_EQ(0.0f, wheelEntity->GetTransform()->GetWorldX());
  114. ASSERT_FALSE(wheelEntity->FindComponent<PrefabTestComponent>());
  115. // Redo
  116. undoNode.Redo();
  117. PropagateAllTemplateChanges();
  118. wheelEntity = AzToolsFramework::GetEntityById(wheelEntityId);
  119. ASSERT_TRUE(overrideInterface->AreOverridesPresent(wheelEntityId));
  120. ASSERT_FLOAT_EQ(10.0f, wheelEntity->GetTransform()->GetWorldX());
  121. ASSERT_TRUE(wheelEntity->FindComponent<PrefabTestComponent>());
  122. }
  123. TEST_F(PrefabUndoEditEntityTests, EditEntityAsOverrideOnAddEntityOverride)
  124. {
  125. // Level <-- focused
  126. // | Car
  127. // | Dummy
  128. // | Entity <-- add-entity override
  129. PrefabOverridePublicInterface* overrideInterface = AZ::Interface<PrefabOverridePublicInterface>::Get();
  130. EXPECT_TRUE(overrideInterface) << "Could not get the override public interface.";
  131. const AZStd::string carPrefabName = "Car";
  132. AZ::IO::Path engineRootPath;
  133. m_settingsRegistryInterface->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
  134. AZ::IO::Path carPrefabFilepath = engineRootPath / carPrefabName;
  135. AZ::EntityId tireEntityId = CreateEditorEntityUnderRoot("Dummy");
  136. AZ::EntityId carContainerId = CreateEditorPrefab(carPrefabFilepath, { tireEntityId });
  137. // Create a new entity as override under the car instance
  138. PrefabEntityResult createEntityResult = m_prefabPublicInterface->CreateEntity(carContainerId, AZ::Vector3());
  139. EXPECT_TRUE(createEntityResult.IsSuccess()) << "Could not add a wheel entity as override.";
  140. AZ::EntityId addedEntityId = createEntityResult.GetValue();
  141. AZ::Entity* addedEntity = AzToolsFramework::GetEntityById(addedEntityId);
  142. EXPECT_TRUE(addedEntity);
  143. InstanceOptionalReference levelRootInstance = m_instanceEntityMapperInterface->FindOwningInstance(GetRootContainerEntityId());
  144. EXPECT_TRUE(levelRootInstance.has_value());
  145. InstanceOptionalReference carInstance = m_instanceEntityMapperInterface->FindOwningInstance(carContainerId);
  146. EXPECT_TRUE(carInstance.has_value());
  147. // Modify the transform component as override
  148. AZ::TransformBus::Event(addedEntityId, &AZ::TransformInterface::SetWorldX, 10.0f);
  149. // Add a new comopnent as override
  150. addedEntity->Deactivate();
  151. addedEntity->AddComponent(aznew PrefabTestComponent());
  152. addedEntity->Activate();
  153. // Create an undo node and redo
  154. PrefabUndoEntityOverrides undoNode("Undo Editing Entity As Override");
  155. undoNode.CaptureAndRedo({ addedEntity }, carInstance->get(), levelRootInstance->get());
  156. PropagateAllTemplateChanges();
  157. // Note for the following code and all other code in this file,
  158. // PropagateAllTemplateChanges() may delete and re-create entities, it is not safe
  159. // to hold onto entity* pointers across this call. You must fetch them by ID again.
  160. addedEntity = AzToolsFramework::GetEntityById(addedEntityId);
  161. ASSERT_TRUE(overrideInterface->AreOverridesPresent(addedEntityId));
  162. ASSERT_FLOAT_EQ(10.0f, addedEntity->GetTransform()->GetWorldX());
  163. ASSERT_TRUE(addedEntity->FindComponent<PrefabTestComponent>());
  164. // Undo
  165. undoNode.Undo();
  166. PropagateAllTemplateChanges();
  167. addedEntity = AzToolsFramework::GetEntityById(addedEntityId);
  168. ASSERT_TRUE(overrideInterface->AreOverridesPresent(addedEntityId)); // The added entity itself is an override edit
  169. ASSERT_FLOAT_EQ(0.0f, addedEntity->GetTransform()->GetWorldX());
  170. ASSERT_FALSE(addedEntity->FindComponent<PrefabTestComponent>());
  171. // Redo
  172. undoNode.Redo();
  173. PropagateAllTemplateChanges();
  174. addedEntity = AzToolsFramework::GetEntityById(addedEntityId);
  175. ASSERT_TRUE(overrideInterface->AreOverridesPresent(addedEntityId));
  176. ASSERT_FLOAT_EQ(10.0f, addedEntity->GetTransform()->GetWorldX());
  177. ASSERT_TRUE(addedEntity->FindComponent<PrefabTestComponent>());
  178. }
  179. } // namespace UnitTest