3
0

SliceEditorEntityOwnershipTests.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  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 <AzToolsFramework/Entity/SliceEditorEntityOwnershipService.h>
  9. #include "EntityOwnershipServiceTestFixture.h"
  10. namespace UnitTest
  11. {
  12. class SliceEditorEntityOwnershipTests
  13. : public EntityOwnershipServiceTestFixture
  14. {
  15. public:
  16. void SetUp() override
  17. {
  18. SetUpEntityOwnershipServiceTest();
  19. m_sliceEditorEntityOwnershipService = AZStd::make_unique<AzToolsFramework::SliceEditorEntityOwnershipService>(
  20. AZ::Uuid::CreateNull(), m_app->GetSerializeContext());
  21. m_sliceEditorEntityOwnershipService->SetEntitiesAddedCallback([this](const AzFramework::EntityList& entityList)
  22. {
  23. this->HandleEntitiesAdded(entityList);
  24. });
  25. m_sliceEditorEntityOwnershipService->SetEntitiesRemovedCallback([this](const AzFramework::EntityIdList& entityIds)
  26. {
  27. this->HandleEntitiesRemoved(entityIds);
  28. });
  29. m_sliceEditorEntityOwnershipService->SetValidateEntitiesCallback([this](const AzFramework::EntityList& entityList)
  30. {
  31. return this->ValidateEntities(entityList);
  32. });
  33. m_sliceEditorEntityOwnershipService->Initialize();
  34. }
  35. void TearDown() override
  36. {
  37. m_sliceEditorEntityOwnershipService->Destroy();
  38. m_sliceEditorEntityOwnershipService.reset();
  39. TearDownEntityOwnershipServiceTest();
  40. }
  41. protected:
  42. AZStd::unique_ptr<AzToolsFramework::SliceEditorEntityOwnershipService> m_sliceEditorEntityOwnershipService;
  43. };
  44. TEST_F(SliceEditorEntityOwnershipTests, Initialize_ResetOwnershipService_CreateRootSlice)
  45. {
  46. m_sliceEditorEntityOwnershipService->Reset();
  47. EXPECT_TRUE(GetRootSliceAsset()->GetComponent() != nullptr);
  48. }
  49. TEST_F(SliceEditorEntityOwnershipTests, OnAssetReloaded_RootAssetReloaded_ReloadEntities)
  50. {
  51. // Clone the root slice asset
  52. AZ::Data::Asset<AZ::SliceAsset> rootSliceAssetClone(GetRootSliceAsset().Get()->Clone(), AZ::Data::AssetLoadBehavior::Default);
  53. AZ::Entity* sliceRootEntity = new AZ::Entity();
  54. AZ::SliceComponent* sliceComponent = sliceRootEntity->CreateComponent<AZ::SliceComponent>();
  55. sliceComponent->SetSerializeContext(m_app->GetSerializeContext());
  56. sliceComponent->AddEntity(aznew AZ::Entity("testEntity"));
  57. rootSliceAssetClone->SetData(sliceRootEntity, sliceComponent);
  58. m_sliceEditorEntityOwnershipService->OnAssetReloaded(rootSliceAssetClone);
  59. // Validate that entities-added callback is triggerted.
  60. EXPECT_TRUE(m_entitiesAddedCallbackTriggered);
  61. const AzFramework::EntityList& entitiesUnderRootSlice = GetRootSliceAsset()->GetComponent()->GetNewEntities();
  62. // Validate that there is only one entity under root slice.
  63. EXPECT_EQ(entitiesUnderRootSlice.size(), 1);
  64. EXPECT_EQ(entitiesUnderRootSlice.at(0)->GetName(), "testEntity");
  65. }
  66. TEST_F(SliceEditorEntityOwnershipTests, LoadFromStream_RemapIdsFalse_IdsNotRemapped)
  67. {
  68. AZ::Entity* rootEntity = aznew AZ::Entity();
  69. AZ::SliceComponent* rootSliceComponent = rootEntity->CreateComponent<AZ::SliceComponent>();
  70. AZ::Entity* testEntity = aznew AZ::Entity();
  71. rootSliceComponent->AddEntity(testEntity);
  72. AZStd::vector<char> charBuffer;
  73. AZ::IO::ByteContainerStream<AZStd::vector<char>> stream(&charBuffer);
  74. AZ::Utils::SaveObjectToStream<AZ::Entity>(stream, AZ::ObjectStream::ST_XML, rootEntity, m_app->GetSerializeContext());
  75. stream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  76. EXPECT_TRUE(m_sliceEditorEntityOwnershipService->LoadFromStream(stream, false));
  77. AZ::SliceComponent::EntityIdToEntityIdMap previousToNewIdMap;
  78. AzFramework::SliceEntityOwnershipServiceRequestBus::BroadcastResult(previousToNewIdMap,
  79. &AzFramework::SliceEntityOwnershipServiceRequestBus::Events::GetLoadedEntityIdMap);
  80. // Verify that remapping of entityIds is not done by comparing the entityIds in previousToNewIdMap
  81. EXPECT_TRUE(previousToNewIdMap.begin()->first == previousToNewIdMap.begin()->second);
  82. delete rootEntity;
  83. }
  84. TEST_F(SliceEditorEntityOwnershipTests, InstantiateEditorSlice_ValidAssetProvided_SliceCreated)
  85. {
  86. AZ::Data::Asset<AZ::SliceAsset> sliceAsset;
  87. sliceAsset.Create(AZ::Data::AssetId(AZ::Uuid::CreateRandom()), false);
  88. AddEditorSlice(sliceAsset, AZ::Transform::CreateIdentity(), EntityList{});
  89. AZ::SliceComponent::SliceList& slicesUnderRootSlice = GetRootSliceAsset()->GetComponent()->GetSlices();
  90. ASSERT_EQ(slicesUnderRootSlice.size(), 1);
  91. // Verify that the created slice has the same asset as the one it's provided to be created with.
  92. EXPECT_EQ(sliceAsset, slicesUnderRootSlice.front().GetSliceAsset());
  93. }
  94. TEST_F(SliceEditorEntityOwnershipTests, PromoteEditorEntitiesIntoSlice_ValidEntitiesProvided_SliceCreated)
  95. {
  96. AZ::Entity* looseEntity = aznew AZ::Entity("testEntity");
  97. m_sliceEditorEntityOwnershipService->AddEntity(looseEntity);
  98. AZ::Entity* entityInSlice = aznew AZ::Entity("testEntity");
  99. AZ::Data::Asset<AZ::SliceAsset> sliceAsset;
  100. sliceAsset.Create(AZ::Data::AssetId(AZ::Uuid::CreateRandom()), false);
  101. AddSliceComponentToAsset(sliceAsset, EntityList{ entityInSlice });
  102. AZ::SliceComponent::EntityIdToEntityIdMap looseEntityIdToSliceAssetEntityIdMap;
  103. looseEntityIdToSliceAssetEntityIdMap.emplace(looseEntity->GetId(), entityInSlice->GetId());
  104. // Verify that no slices exist.
  105. AZ::SliceComponent::SliceList& slicesUnderRootSlice = GetRootSliceAsset()->GetComponent()->GetSlices();
  106. ASSERT_EQ(slicesUnderRootSlice.size(), 0);
  107. AzToolsFramework::SliceEditorEntityOwnershipServiceRequestBus::Broadcast(
  108. &AzToolsFramework::SliceEditorEntityOwnershipServiceRequestBus::Events::PromoteEditorEntitiesIntoSlice,
  109. sliceAsset, looseEntityIdToSliceAssetEntityIdMap);
  110. // Verify that one slice is created.
  111. slicesUnderRootSlice = GetRootSliceAsset()->GetComponent()->GetSlices();
  112. ASSERT_EQ(slicesUnderRootSlice.size(), 1);
  113. AZ::SliceComponent::SliceReference& sliceReference = slicesUnderRootSlice.front();
  114. // Verify that there exists one slice instance with one entity and the correct slice asset.
  115. ASSERT_EQ(sliceAsset, sliceReference.GetSliceAsset());
  116. ASSERT_EQ(sliceReference.GetInstances().size(), 1);
  117. AzFramework::EntityList entitiesOfSlice = sliceReference.GetInstances().begin()->GetInstantiated()->m_entities;
  118. ASSERT_EQ(entitiesOfSlice.size(), 1);
  119. // Verify that the entity in the created slice has the same id of the provided test entity.
  120. EXPECT_EQ(entitiesOfSlice[0]->GetId(), looseEntity->GetId());
  121. }
  122. TEST_F(SliceEditorEntityOwnershipTests, DetachSliceEntities_ValidEntitiesProvided_EntitiesDetached)
  123. {
  124. AZ::Data::Asset<AZ::SliceAsset> sliceAsset;
  125. sliceAsset.Create(AZ::Data::AssetId(AZ::Uuid::CreateRandom()), false);
  126. AZ::Entity* entityInSlice = aznew AZ::Entity("testEntity");
  127. AddEditorSlice(sliceAsset, AZ::Transform::CreateIdentity(), EntityList{ entityInSlice });
  128. // Verify that one slice is created and it has one editor entity
  129. AZ::SliceComponent::SliceList& slicesUnderRootSlice = GetRootSliceAsset()->GetComponent()->GetSlices();
  130. ASSERT_EQ(slicesUnderRootSlice.size(), 1);
  131. AZ::SliceComponent::SliceReference& sliceReference = slicesUnderRootSlice.front();
  132. AzFramework::EntityList entitiesOfSlice = sliceReference.GetInstances().begin()->GetInstantiated()->m_entities;
  133. ASSERT_EQ(entitiesOfSlice.size(), 1);
  134. // Verify that owning slice for the editor entity exists.
  135. AZ::SliceComponent::SliceInstanceAddress sliceInstanceAddressBeforeDetach;
  136. AzFramework::SliceEntityRequestBus::EventResult(sliceInstanceAddressBeforeDetach, entitiesOfSlice[0]->GetId(),
  137. &AzFramework::SliceEntityRequestBus::Events::GetOwningSlice);
  138. EXPECT_TRUE(sliceInstanceAddressBeforeDetach.IsValid());
  139. AzToolsFramework::SliceEditorEntityOwnershipServiceRequestBus::Broadcast(
  140. &AzToolsFramework::SliceEditorEntityOwnershipServiceRequestBus::Events::DetachSliceEntities,
  141. AzToolsFramework::EntityIdList{ entitiesOfSlice[0]->GetId() });
  142. // Verify that owning slice for the editor entity doesn't exist.
  143. AZ::SliceComponent::SliceInstanceAddress sliceInstanceAddressAfterDetach;
  144. AzFramework::SliceEntityRequestBus::EventResult(sliceInstanceAddressAfterDetach, entitiesOfSlice[0]->GetId(),
  145. &AzFramework::SliceEntityRequestBus::Events::GetOwningSlice);
  146. EXPECT_FALSE(sliceInstanceAddressAfterDetach.IsValid());
  147. }
  148. TEST_F(SliceEditorEntityOwnershipTests, DetachSliceInstances_ValidInstanceProvided_InstanceDetached)
  149. {
  150. AZ::Data::Asset<AZ::SliceAsset> sliceAsset;
  151. sliceAsset.Create(AZ::Data::AssetId(AZ::Uuid::CreateRandom()), false);
  152. AZ::Entity* testEntity = aznew AZ::Entity("testEntity");
  153. AddEditorSlice(sliceAsset, AZ::Transform::CreateIdentity(), EntityList{ testEntity });
  154. // Verify that one slice exists before detaching it.
  155. AZ::SliceComponent::SliceList& slicesUnderRootSlice = GetRootSliceAsset()->GetComponent()->GetSlices();
  156. ASSERT_EQ(slicesUnderRootSlice.front().GetInstances().size(), 1);
  157. // Verify that there are no loose entities in the editor.
  158. EntityList looseEntitiesBeforeDetach;
  159. m_sliceEditorEntityOwnershipService->GetNonPrefabEntities(looseEntitiesBeforeDetach);
  160. EXPECT_TRUE(looseEntitiesBeforeDetach.size() == 0);
  161. AZ::SliceComponent::SliceReference& sliceReference = slicesUnderRootSlice.front();
  162. auto sliceInstanceIterator = sliceReference.GetInstances().begin();
  163. AZ::SliceComponent::SliceInstanceAddress sliceInstanceAddress(&sliceReference, &(*sliceInstanceIterator));
  164. // Verify that there is one entity in the slice that is about to be detached.
  165. EntityList entitiesInsliceBeforeDetach = sliceInstanceIterator->GetInstantiated()->m_entities;
  166. EXPECT_TRUE(entitiesInsliceBeforeDetach.size() == 1);
  167. AzToolsFramework::SliceEditorEntityOwnershipServiceRequestBus::Broadcast(
  168. &AzToolsFramework::SliceEditorEntityOwnershipServiceRequestBus::Events::DetachSliceInstances,
  169. AZ::SliceComponent::SliceInstanceAddressSet{ sliceInstanceAddress });
  170. // Verify that the only slice that existed is not there anymore after detaching it.
  171. slicesUnderRootSlice = GetRootSliceAsset()->GetComponent()->GetSlices();
  172. EXPECT_EQ(slicesUnderRootSlice.front().GetInstances().size(), 0);
  173. // Verify that that the detached slice entity is now a loose entity in the editor.
  174. EntityList looseEntitiesAfterDetach;
  175. m_sliceEditorEntityOwnershipService->GetNonPrefabEntities(looseEntitiesAfterDetach);
  176. EXPECT_TRUE(looseEntitiesAfterDetach.size() == 1);
  177. EXPECT_EQ(entitiesInsliceBeforeDetach[0]->GetId(), looseEntitiesAfterDetach[0]->GetId());
  178. }
  179. TEST_F(SliceEditorEntityOwnershipTests, RestoreSliceEntity_SliceEntityDeleted_SliceEntityRestored)
  180. {
  181. AZ::Data::Asset<AZ::SliceAsset> sliceAsset;
  182. sliceAsset.Create(AZ::Data::AssetId(AZ::Uuid::CreateRandom()), false);
  183. AZ::Entity* testEntity = aznew AZ::Entity("testEntity");
  184. AddEditorSlice(sliceAsset, AZ::Transform::CreateIdentity(), EntityList{ testEntity });
  185. // Verify that one slice exists
  186. AZ::SliceComponent::SliceList& slicesUnderRootSlice = GetRootSliceAsset()->GetComponent()->GetSlices();
  187. ASSERT_EQ(slicesUnderRootSlice.front().GetInstances().size(), 1);
  188. AZ::SliceComponent::SliceReference& sliceReference = slicesUnderRootSlice.front();
  189. // Verify that one entity exists in the slice
  190. EntityList entitiesOfSlice = sliceReference.GetInstances().begin()->GetInstantiated()->m_entities;
  191. ASSERT_EQ(entitiesOfSlice.size(), 1);
  192. // Get the slice entity ancestor and slice instance id before destroying the entity of the slice
  193. AZ::SliceComponent::EntityAncestorList entityAncestorList;
  194. sliceReference.GetInstanceEntityAncestry(entitiesOfSlice.front()->GetId(), entityAncestorList);
  195. AZ::SliceComponent::SliceInstanceId sliceInstanceId = sliceReference.GetInstances().begin()->GetId();
  196. m_sliceEditorEntityOwnershipService->DestroyEntityById(entitiesOfSlice.front()->GetId());
  197. // Verify that no slices exists after slice entity is destroyed.
  198. ASSERT_EQ(slicesUnderRootSlice.size(), 0);
  199. // Restore the slice entity
  200. AZ::SliceComponent::EntityRestoreInfo entityRestoreInfo = AZ::SliceComponent::EntityRestoreInfo(
  201. sliceAsset, sliceInstanceId, entityAncestorList.front().m_entity->GetId(), AZ::DataPatch::FlagsMap{});
  202. AzToolsFramework::SliceEditorEntityOwnershipServiceRequestBus::Broadcast(
  203. &AzToolsFramework::SliceEditorEntityOwnershipServiceRequestBus::Events::RestoreSliceEntity,
  204. entitiesOfSlice.front(),
  205. entityRestoreInfo,
  206. AzToolsFramework::SliceEntityRestoreType::Deleted);
  207. AZ::TickBus::ExecuteQueuedEvents();
  208. // Verify that slice is restored with the same entity it had before.
  209. ASSERT_EQ(slicesUnderRootSlice.size(), 1);
  210. EntityList entitiesOfSliceAfterRestore = sliceReference.GetInstances().begin()->GetInstantiated()->m_entities;
  211. ASSERT_EQ(entitiesOfSliceAfterRestore.size(), 1);
  212. EXPECT_EQ(entitiesOfSliceAfterRestore.front()->GetId(), entitiesOfSlice.front()->GetId());
  213. }
  214. }