123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <AzToolsFramework/ToolsComponents/TransformComponent.h>
- #include <AzToolsFramework/Prefab/PrefabDomUtils.h>
- #include <Prefab/PrefabTestFixture.h>
- namespace UnitTest
- {
- using InstanceDeserializationTest = PrefabTestFixture;
- using InstanceUniquePointer = AZStd::unique_ptr<AzToolsFramework::Prefab::Instance>;
- static void GenerateDomAndReloadInstantiatedPrefab(InstanceUniquePointer& createdPrefab, InstanceUniquePointer& instantiatedPrefab)
- {
- PrefabDom tempDomForStoringAndLoading;
- PrefabDomUtils::StoreInstanceInPrefabDom(*createdPrefab, tempDomForStoringAndLoading);
- PrefabDomUtils::LoadInstanceFromPrefabDom(
- *instantiatedPrefab, tempDomForStoringAndLoading, PrefabDomUtils::LoadFlags::UseSelectiveDeserialization);
- }
- AZStd::pair<InstanceUniquePointer, InstanceUniquePointer> SetupPrefabInstances(
- const AzToolsFramework::EntityList& entitiesToUseForCreation,
- AZStd::vector<AZStd::unique_ptr<Instance>>&& nestedInstances, PrefabSystemComponent* prefabSystemComponent)
- {
- AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> createdPrefab =
- prefabSystemComponent->CreatePrefab(entitiesToUseForCreation, AZStd::move(nestedInstances), "test/path");
- EXPECT_NE(nullptr, createdPrefab);
- AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> instantiatedPrefab =
- prefabSystemComponent->InstantiatePrefab(createdPrefab->GetTemplateId());
- EXPECT_NE(nullptr, instantiatedPrefab);
- instantiatedPrefab->GetAllEntitiesInHierarchy(
- [](const AZStd::unique_ptr<AZ::Entity>& entity)
- {
- // Activate the entities so that we can later validate that entities stay activated throughout the deserialization.
- entity->Init();
- entity->Activate();
- return true;
- });
- return { AZStd::move(createdPrefab), AZStd::move(instantiatedPrefab) };
- }
- static void ValidateEntityState(
- const InstanceUniquePointer& instanceToLookUnder, AZStd::string_view entityName, AZ::Entity::State expectedEntityState)
- {
- bool isEntityFound = false;
- instanceToLookUnder->GetEntities(
- [&isEntityFound, &entityName, &expectedEntityState](const AZStd::unique_ptr<AZ::Entity>& entity)
- {
- if (entity->GetName() == entityName)
- {
- EXPECT_EQ(entity->GetState(), expectedEntityState);
- isEntityFound = true;
- }
- return true;
- });
- EXPECT_TRUE(isEntityFound);
- }
- static void ValidateTransformComponentValue(const AZStd::unique_ptr<AZ::Entity>& entity, const float worldXValue)
- {
- // Validate that the entity is in 'constructed' state, which indicates that it got reloaded.
- EXPECT_EQ(entity->GetState(), AZ::Entity::State::Constructed);
- AZ::Entity::ComponentArrayType entityComponents = entity->GetComponents();
- EXPECT_EQ(1, entityComponents.size());
- AzToolsFramework::Components::TransformComponent* transformComponentInInstantiatedPrefab =
- reinterpret_cast<AzToolsFramework::Components::TransformComponent*>(entityComponents.front());
- EXPECT_NE(nullptr, transformComponentInInstantiatedPrefab);
- // Validate that the transform component is correctly updated after reloading.
- EXPECT_EQ(transformComponentInInstantiatedPrefab->GetWorldX(), worldXValue);
- }
- TEST_F(InstanceDeserializationTest, ReloadInstanceUponComponentUpdate)
- {
- AZ::Entity* entity1 = CreateEntity("Entity1", false);
- AzToolsFramework::Components::TransformComponent* transformComponent = aznew AzToolsFramework::Components::TransformComponent;
- transformComponent->SetWorldTranslation(AZ::Vector3(10.0, 0, 0));
- entity1->AddComponent(transformComponent);
- AZ::Entity* entity2 = CreateEntity("Entity2", false);
- AZStd::pair<InstanceUniquePointer, InstanceUniquePointer> prefabInstances =
- SetupPrefabInstances(AzToolsFramework::EntityList{ entity1, entity2 }, {}, m_prefabSystemComponent);
- InstanceUniquePointer createdPrefab = AZStd::move(prefabInstances.first);
- InstanceUniquePointer instantiatedPrefab = AZStd::move(prefabInstances.second);
- createdPrefab->GetEntities(
- [](const AZStd::unique_ptr<AZ::Entity>& entity)
- {
- if (entity->GetName() == "Entity1")
- {
- // Activate the entity to access the transform interface and use it to modify the transform component.
- entity->Init();
- entity->Activate();
- AZ::TransformBus::Event(entity->GetId(), &AZ::TransformInterface::SetWorldX, 20.0f);
- }
- return true;
- });
- GenerateDomAndReloadInstantiatedPrefab(createdPrefab, instantiatedPrefab);
- instantiatedPrefab->GetEntities(
- [](const AZStd::unique_ptr<AZ::Entity>& entity)
- {
- if (entity->GetName() == "Entity2")
- {
- // Since we didn't touch entity2 in createdPrefab, it should remain untouched in instantiatedPrefab and thus retain its
- // active state.
- EXPECT_EQ(entity->GetState(), AZ::Entity::State::Active);
- }
- else if (entity->GetName() == "Entity1")
- {
- ValidateTransformComponentValue(entity, 20.0f);
- }
- return true;
- });
- }
- TEST_F(InstanceDeserializationTest, ReloadInstanceWithCachedDom)
- {
- AZ::Entity* entity1 = CreateEntity("Entity1", false);
- AzToolsFramework::Components::TransformComponent* transformComponent = aznew AzToolsFramework::Components::TransformComponent;
- transformComponent->SetWorldTranslation(AZ::Vector3(10.0, 0, 0));
- entity1->AddComponent(transformComponent);
- AZStd::pair<InstanceUniquePointer, InstanceUniquePointer> prefabInstances =
- SetupPrefabInstances(AzToolsFramework::EntityList{ entity1 }, {}, m_prefabSystemComponent);
- InstanceUniquePointer createdPrefab = AZStd::move(prefabInstances.first);
- createdPrefab->GetEntities(
- [](const AZStd::unique_ptr<AZ::Entity>& entity)
- {
- if (entity->GetName() == "Entity1")
- {
- // Activate the entity to access the transform interface and use it to modify the transform component.
- entity->Init();
- entity->Activate();
- AZ::TransformBus::Event(entity->GetId(), &AZ::TransformInterface::SetWorldX, 20.0f);
- }
- return true;
- });
- PrefabDom tempDomForStoringAndLoading;
- PrefabDomUtils::StoreInstanceInPrefabDom(*createdPrefab, tempDomForStoringAndLoading);
- createdPrefab->SetCachedInstanceDom(tempDomForStoringAndLoading);
- PrefabDomUtils::LoadInstanceFromPrefabDom(
- *createdPrefab, tempDomForStoringAndLoading, PrefabDomUtils::LoadFlags::UseSelectiveDeserialization);
- createdPrefab->GetEntities(
- [](const AZStd::unique_ptr<AZ::Entity>& entity)
- {
- // Since we updated the cached dom, entities should remain untouched in createdPrefab and thus retain their
- // active state.
- EXPECT_EQ(entity->GetState(), AZ::Entity::State::Active);
- return true;
- });
- }
- TEST_F(InstanceDeserializationTest, ReloadInstanceUponComponentAdd)
- {
- AZ::Entity* entity1 = CreateEntity("Entity1", false);
- AZ::Entity* entity2 = CreateEntity("Entity2", false);
- AZStd::pair<InstanceUniquePointer, InstanceUniquePointer> prefabInstances =
- SetupPrefabInstances(AzToolsFramework::EntityList{ entity1, entity2 }, {}, m_prefabSystemComponent);
- InstanceUniquePointer createdPrefab = AZStd::move(prefabInstances.first);
- InstanceUniquePointer instantiatedPrefab = AZStd::move(prefabInstances.second);
- createdPrefab->GetEntities(
- [](const AZStd::unique_ptr<AZ::Entity>& entity)
- {
- if (entity->GetName() == "Entity1")
- {
- // Add a transform component to entity1 of createdPrefab.
- entity->CreateComponent(AZ::EditorTransformComponentTypeId);
- }
- return true;
- });
- GenerateDomAndReloadInstantiatedPrefab(createdPrefab, instantiatedPrefab);
- instantiatedPrefab->GetEntities(
- [](const AZStd::unique_ptr<AZ::Entity>& entity)
- {
- if (entity->GetName() == "Entity2")
- {
- // Since we didn't touch entity2 in createdPrefab, it should remain untouched in instantiatedPrefab and thus retain its
- // active state.
- EXPECT_EQ(entity->GetState(), AZ::Entity::State::Active);
- }
- else if (entity->GetName() == "Entity1")
- {
- // Validate that the entity is in 'constructed' state, which indicates that it got reloaded.
- EXPECT_EQ(entity->GetState(), AZ::Entity::State::Constructed);
- AZ::Entity::ComponentArrayType entity1Components = entity->GetComponents();
- EXPECT_EQ(1, entity1Components.size());
- AzToolsFramework::Components::TransformComponent* transformComponentInInstantiatedPrefab =
- reinterpret_cast<AzToolsFramework::Components::TransformComponent*>(entity1Components.front());
- // Validate that a transform component exists in entity1 of instantiatedPrefab.
- EXPECT_TRUE(transformComponentInInstantiatedPrefab != nullptr);
- }
- return true;
- });
- }
- TEST_F(InstanceDeserializationTest, ReloadInstanceUponComponentDelete)
- {
- AZ::Entity* entity1 = CreateEntity("Entity1", false);
- AzToolsFramework::Components::TransformComponent* transformComponent = aznew AzToolsFramework::Components::TransformComponent;
- transformComponent->SetWorldTranslation(AZ::Vector3(10.0, 0, 0));
- entity1->AddComponent(transformComponent);
- AZ::Entity* entity2 = CreateEntity("Entity2", false);
- AZStd::pair<InstanceUniquePointer, InstanceUniquePointer> prefabInstances =
- SetupPrefabInstances(AzToolsFramework::EntityList{ entity1, entity2 }, {}, m_prefabSystemComponent);
- InstanceUniquePointer createdPrefab = AZStd::move(prefabInstances.first);
- InstanceUniquePointer instantiatedPrefab = AZStd::move(prefabInstances.second);
- createdPrefab->GetEntities(
- [](const AZStd::unique_ptr<AZ::Entity>& entity)
- {
- if (entity->GetName() == "Entity1")
- {
- // Remove the transform component from entity1 of createdPrefab;
- AZ::Component* transformComponent = entity->GetComponents().front();
- EXPECT_NE(nullptr, transformComponent);
- entity->RemoveComponent(transformComponent);
- delete transformComponent;
- transformComponent = nullptr;
- }
- return true;
- });
- GenerateDomAndReloadInstantiatedPrefab(createdPrefab, instantiatedPrefab);
- instantiatedPrefab->GetEntities(
- [](const AZStd::unique_ptr<AZ::Entity>& entity)
- {
- if (entity->GetName() == "Entity2")
- {
- // Since we didn't touch entity2 in createdPrefab, it should remain untouched in instantiatedPrefab and thus retain its
- // active state.
- EXPECT_EQ(entity->GetState(), AZ::Entity::State::Active);
- }
- else if (entity->GetName() == "Entity1")
- {
- EXPECT_EQ(entity->GetState(), AZ::Entity::State::Constructed);
- AZ::Entity::ComponentArrayType entity1Components = entity->GetComponents();
- // Validate that the transform component can't be found in entity1 of instantiatedPrefab.
- EXPECT_TRUE(entity1Components.empty());
- }
- return true;
- });
- }
- TEST_F(InstanceDeserializationTest, ReloadInstanceUponAddingEntityToExistingEntities)
- {
- AZ::Entity* entity1 = CreateEntity("Entity1", false);
- AZStd::pair<InstanceUniquePointer, InstanceUniquePointer> prefabInstances =
- SetupPrefabInstances(AzToolsFramework::EntityList{ entity1 }, {}, m_prefabSystemComponent);
- InstanceUniquePointer createdPrefab = AZStd::move(prefabInstances.first);
- InstanceUniquePointer instantiatedPrefab = AZStd::move(prefabInstances.second);
- createdPrefab->AddEntity(AZStd::move(AZStd::make_unique<AZ::Entity>("Entity2")));
- GenerateDomAndReloadInstantiatedPrefab(createdPrefab, instantiatedPrefab);
- bool isEntity1Found = false, isEntity2Found = false;
- instantiatedPrefab->GetEntities(
- [&isEntity1Found, &isEntity2Found](const AZStd::unique_ptr<AZ::Entity>& entity)
- {
- if (entity->GetName() == "Entity1")
- {
- // Since we didn't touch entity1 in createdPrefab, it should remain untouched in instantiatedPrefab and thus retain its
- // active state.
- EXPECT_EQ(entity->GetState(), AZ::Entity::State::Active);
- isEntity1Found = true;
- }
- else if (entity->GetName() == "Entity2")
- {
- // Validate that the entity2 is in 'constructed' state, which indicates that it got added from dom.
- EXPECT_EQ(entity->GetState(), AZ::Entity::State::Constructed);
- isEntity2Found = true;
- }
- return true;
- });
- EXPECT_TRUE(isEntity1Found);
- EXPECT_TRUE(isEntity2Found);
- }
- TEST_F(InstanceDeserializationTest, ReloadInstanceUponAddingTheFirstEntity)
- {
- AZStd::pair<InstanceUniquePointer, InstanceUniquePointer> prefabInstances =
- SetupPrefabInstances(AzToolsFramework::EntityList{}, {}, m_prefabSystemComponent);
- InstanceUniquePointer createdPrefab = AZStd::move(prefabInstances.first);
- InstanceUniquePointer instantiatedPrefab = AZStd::move(prefabInstances.second);
- createdPrefab->AddEntity(AZStd::move(AZStd::make_unique<AZ::Entity>("Entity1")));
- GenerateDomAndReloadInstantiatedPrefab(createdPrefab, instantiatedPrefab);
- bool isEntity1Found = false;
- instantiatedPrefab->GetEntities(
- [&isEntity1Found](const AZStd::unique_ptr<AZ::Entity>& entity)
- {
- if (entity->GetName() == "Entity1")
- {
- isEntity1Found = true;
- }
- return true;
- });
- EXPECT_TRUE(isEntity1Found);
- }
- TEST_F(InstanceDeserializationTest, ReloadInstanceUponDeletingOneAmongManyEntities)
- {
- AZ::Entity* entity1 = CreateEntity("Entity1", false);
- AZ::Entity* entity2 = CreateEntity("Entity2", false);
- AZStd::pair<InstanceUniquePointer, InstanceUniquePointer> prefabInstances =
- SetupPrefabInstances(AzToolsFramework::EntityList{ entity1, entity2 }, {}, m_prefabSystemComponent);
- InstanceUniquePointer createdPrefab = AZStd::move(prefabInstances.first);
- InstanceUniquePointer instantiatedPrefab = AZStd::move(prefabInstances.second);
- createdPrefab->DetachEntity(entity2->GetId());
- GenerateDomAndReloadInstantiatedPrefab(createdPrefab, instantiatedPrefab);
- bool isEntity1Found = false, isEntity2Found = false;
- instantiatedPrefab->GetEntities(
- [&isEntity1Found, &isEntity2Found](const AZStd::unique_ptr<AZ::Entity>& entity)
- {
- if (entity->GetName() == "Entity1")
- {
- // Since we didn't touch entity1 in createdPrefab, it should remain untouched in instantiatedPrefab and thus retain its
- // active state.
- EXPECT_EQ(entity->GetState(), AZ::Entity::State::Active);
- isEntity1Found = true;
- }
- else if (entity->GetName() == "Entity2")
- {
- // This shouldn't be hit since Entity2 should have been removed. Mark the boolean as true and throw an error later.
- isEntity2Found = true;
- }
- return true;
- });
- EXPECT_TRUE(isEntity1Found);
- EXPECT_FALSE(isEntity2Found);
- }
- TEST_F(InstanceDeserializationTest, ReloadInstanceUponDeletingTheOnlyEntity)
- {
- AZ::Entity* entity1 = CreateEntity("Entity1", false);
- AZStd::pair<InstanceUniquePointer, InstanceUniquePointer> prefabInstances =
- SetupPrefabInstances(AzToolsFramework::EntityList{ entity1 }, {}, m_prefabSystemComponent);
- InstanceUniquePointer createdPrefab = AZStd::move(prefabInstances.first);
- InstanceUniquePointer instantiatedPrefab = AZStd::move(prefabInstances.second);
- createdPrefab->DetachEntity(entity1->GetId());
- GenerateDomAndReloadInstantiatedPrefab(createdPrefab, instantiatedPrefab);
- bool isEntity1Found = false;
- instantiatedPrefab->GetEntities(
- [&isEntity1Found](const AZStd::unique_ptr<AZ::Entity>& entity)
- {
- if (entity->GetName() == "Entity1")
- {
- // Since we didn't touch entity1 in createdPrefab, it should remain untouched in instantiatedPrefab and thus retain its
- // active state.
- EXPECT_EQ(entity->GetState(), AZ::Entity::State::Active);
- isEntity1Found = true;
- }
- return true;
- });
- EXPECT_FALSE(isEntity1Found);
- }
- TEST_F(InstanceDeserializationTest, ReloadInstanceUponAddingTheFirstNestedInstance)
- {
- AZ::Entity* entity1 = CreateEntity("Entity1", false);
- AZStd::pair<InstanceUniquePointer, InstanceUniquePointer> prefabInstances =
- SetupPrefabInstances(AzToolsFramework::EntityList{ entity1 }, {}, m_prefabSystemComponent);
- InstanceUniquePointer createdPrefab = AZStd::move(prefabInstances.first);
- InstanceUniquePointer instantiatedPrefab = AZStd::move(prefabInstances.second);
- AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> nestedPrefab = m_prefabSystemComponent->CreatePrefab(
- AzToolsFramework::EntityList{ CreateEntity("Entity1", false) }, {}, "test/nestedPrefabPath");
- // Extract the template id from the instance and store it in a variable before moving the instance.
- TemplateId nestedPrefabTemplateId = nestedPrefab->GetTemplateId();
- createdPrefab->AddInstance(AZStd::move(nestedPrefab));
- GenerateDomAndReloadInstantiatedPrefab(createdPrefab, instantiatedPrefab);
- // Validate that the entity remains in active state throughout the reloading process. This indicates that it is untouched.
- ValidateEntityState(instantiatedPrefab, "Entity1", AZ::Entity::State::Active);
- // Validate that there is one instance after reloading the instantiated prefab.
- EXPECT_EQ(instantiatedPrefab->GetNestedInstanceAliases(nestedPrefabTemplateId).size(), 1);
- }
- TEST_F(InstanceDeserializationTest, ReloadInstanceUponAddingNestedInstanceToExistingNestedInstances)
- {
- AZ::Entity* entity1 = CreateEntity("EntityUnderParentPrefab", false);
- InstanceUniquePointer nestedInstanceToUseForCreation = m_prefabSystemComponent->CreatePrefab(
- AzToolsFramework::EntityList{ CreateEntity("EntityUnderNestedPrefab", false) }, {}, "test/nestedPrefabPath");
- // Extract the template id from the instance and store it in a variable before moving the instance.
- TemplateId nestedPrefabTemplateId = nestedInstanceToUseForCreation->GetTemplateId();
- AZStd::vector<InstanceUniquePointer> nestedInstances;
- nestedInstances.emplace_back(AZStd::move(nestedInstanceToUseForCreation));
-
- AZStd::pair<InstanceUniquePointer, InstanceUniquePointer> prefabInstances = SetupPrefabInstances(
- AzToolsFramework::EntityList{ entity1 }, AZStd::move(nestedInstances),
- m_prefabSystemComponent);
- InstanceUniquePointer createdPrefab = AZStd::move(prefabInstances.first);
- InstanceUniquePointer instantiatedPrefab = AZStd::move(prefabInstances.second);
- ASSERT_EQ(instantiatedPrefab->GetNestedInstanceAliases(nestedPrefabTemplateId).size(), 1);
- InstanceUniquePointer nestedInstanceToAdd = m_prefabSystemComponent->InstantiatePrefab(nestedPrefabTemplateId);
- Instance& instanceAdded = createdPrefab->AddInstance(AZStd::move(nestedInstanceToAdd));
- InstanceAlias aliasOfInstanceAdded = instanceAdded.GetInstanceAlias();
- GenerateDomAndReloadInstantiatedPrefab(createdPrefab, instantiatedPrefab);
- // Validate that the entity remains in active state throughout the reloading process. This indicates that it is untouched.
- ValidateEntityState(instantiatedPrefab, "EntityUnderParentPrefab", AZ::Entity::State::Active);
- // Validate that there are two instances after reloading the instantiated prefab.
- EXPECT_EQ(instantiatedPrefab->GetNestedInstanceAliases(nestedPrefabTemplateId).size(), 2);
- instantiatedPrefab->GetNestedInstances(
- [&aliasOfInstanceAdded](AZStd::unique_ptr<Instance>& nestedInstance)
- {
- if (nestedInstance->GetInstanceAlias() == aliasOfInstanceAdded)
- {
- // Entities under a newly deserialized instance should be in constructed state.
- ValidateEntityState(nestedInstance, "EntityUnderNestedPrefab", AZ::Entity::State::Constructed);
- }
- else
- {
- // Entities under an existing nested instance should be in active state. This indicates that the instance is untouched.
- ValidateEntityState(nestedInstance, "EntityUnderNestedPrefab", AZ::Entity::State::Active);
- }
-
- });
- }
- TEST_F(InstanceDeserializationTest, ReloadInstanceUponDeletingTheOnlyNestedInstance)
- {
- AZ::Entity* entity1 = CreateEntity("EntityUnderParentPrefab", false);
- InstanceUniquePointer nestedInstanceToUseForCreation = m_prefabSystemComponent->CreatePrefab(
- AzToolsFramework::EntityList{ CreateEntity("EntityUnderNestedPrefab", false) }, {}, "test/nestedPrefabPath");
- // Extract the template id from the instance and store it in a variable before moving the instance.
- TemplateId nestedPrefabTemplateId = nestedInstanceToUseForCreation->GetTemplateId();
- AZStd::vector<InstanceUniquePointer> nestedInstances;
- nestedInstances.emplace_back(AZStd::move(nestedInstanceToUseForCreation));
- AZStd::pair<InstanceUniquePointer, InstanceUniquePointer> prefabInstances =
- SetupPrefabInstances(AzToolsFramework::EntityList{ entity1 }, AZStd::move(nestedInstances), m_prefabSystemComponent);
- InstanceUniquePointer createdPrefab = AZStd::move(prefabInstances.first);
- InstanceUniquePointer instantiatedPrefab = AZStd::move(prefabInstances.second);
- ASSERT_EQ(createdPrefab->GetNestedInstanceAliases(nestedPrefabTemplateId).size(), 1);
- InstanceUniquePointer nestedInstanceToRemove =
- createdPrefab->DetachNestedInstance(createdPrefab->GetNestedInstanceAliases(nestedPrefabTemplateId).front());
- nestedInstanceToRemove.reset();
- GenerateDomAndReloadInstantiatedPrefab(createdPrefab, instantiatedPrefab);
- // Validate that the entity remains in active state throughout the reloading process. This indicates that it is untouched.
- ValidateEntityState(instantiatedPrefab, "EntityUnderParentPrefab", AZ::Entity::State::Active);
- // Validate that the only nested instance was removed.
- EXPECT_EQ(instantiatedPrefab->GetNestedInstanceAliases(nestedPrefabTemplateId).size(), 0);
- }
- TEST_F(InstanceDeserializationTest, ReloadInstanceUponDeletingOneAmongManyNestedInstances)
- {
- AZ::Entity* entity1 = CreateEntity("EntityUnderParentPrefab", false);
- InstanceUniquePointer nestedInstance1 = m_prefabSystemComponent->CreatePrefab(
- AzToolsFramework::EntityList{ CreateEntity("EntityUnderNestedPrefab", false) }, {}, "test/nestedPrefabPath");
- // Extract the template id from the instance and store it in a variable before moving the instance.
- TemplateId nestedPrefabTemplateId = nestedInstance1->GetTemplateId();
- InstanceUniquePointer nestedInstance2 = m_prefabSystemComponent->InstantiatePrefab(nestedPrefabTemplateId);
- AZStd::vector<InstanceUniquePointer> nestedInstances;
- nestedInstances.emplace_back(AZStd::move(nestedInstance1));
- nestedInstances.emplace_back(AZStd::move(nestedInstance2));
- AZStd::pair<InstanceUniquePointer, InstanceUniquePointer> prefabInstances =
- SetupPrefabInstances(AzToolsFramework::EntityList{ entity1 }, AZStd::move(nestedInstances), m_prefabSystemComponent);
- InstanceUniquePointer createdPrefab = AZStd::move(prefabInstances.first);
- InstanceUniquePointer instantiatedPrefab = AZStd::move(prefabInstances.second);
- AZStd::vector<InstanceAlias> nestedInstanceAliases = createdPrefab->GetNestedInstanceAliases(nestedPrefabTemplateId);
- ASSERT_EQ(nestedInstanceAliases.size(), 2);
- InstanceUniquePointer nestedInstanceToRemove = createdPrefab->DetachNestedInstance(nestedInstanceAliases.front());
- nestedInstanceToRemove.reset();
- GenerateDomAndReloadInstantiatedPrefab(createdPrefab, instantiatedPrefab);
- // Validate that the entity remains in active state throughout the reloading process. This indicates that it is untouched.
- ValidateEntityState(instantiatedPrefab, "EntityUnderParentPrefab", AZ::Entity::State::Active);
- // Validate that the number of instances came down to just one.
- EXPECT_EQ(instantiatedPrefab->GetNestedInstanceAliases(nestedPrefabTemplateId).size(), 1);
- instantiatedPrefab->GetNestedInstances(
- [&nestedInstanceAliases](AZStd::unique_ptr<Instance>& nestedInstance)
- {
- if (nestedInstance->GetInstanceAlias() == nestedInstanceAliases.back())
- {
- // Entities under an existing nested instance should be in active state. This indicates that the instance is untouched.
- ValidateEntityState(nestedInstance, "EntityUnderNestedPrefab", AZ::Entity::State::Active);
- }
- });
- }
- TEST_F(InstanceDeserializationTest, ReloadInstanceUponNestedInstanceEntityUpdate)
- {
- AZ::Entity* entityUnderParentPrefab = CreateEntity("EntityUnderParentPrefab", false);
- AZ::Entity* entityUnderNestedPrefab = CreateEntity("EntityUnderNestedPrefab", false);
- entityUnderNestedPrefab->CreateComponent(AZ::EditorTransformComponentTypeId);
- InstanceUniquePointer nestedInstanceToUseForCreation =
- m_prefabSystemComponent->CreatePrefab(AzToolsFramework::EntityList{ entityUnderNestedPrefab }, {}, "test/nestedPrefabPath");
- // Extract the template id from the instance and store it in a variable before moving the instance.
- TemplateId nestedPrefabTemplateId = nestedInstanceToUseForCreation->GetTemplateId();
- AZStd::vector<InstanceUniquePointer> nestedInstances;
- nestedInstances.emplace_back(AZStd::move(nestedInstanceToUseForCreation));
- AZStd::pair<InstanceUniquePointer, InstanceUniquePointer> prefabInstances = SetupPrefabInstances(
- AzToolsFramework::EntityList{ entityUnderParentPrefab }, AZStd::move(nestedInstances), m_prefabSystemComponent);
- InstanceUniquePointer createdPrefab = AZStd::move(prefabInstances.first);
- InstanceUniquePointer instantiatedPrefab = AZStd::move(prefabInstances.second);
- ASSERT_EQ(instantiatedPrefab->GetNestedInstanceAliases(nestedPrefabTemplateId).size(), 1);
- // Activate the entity to access the transform interface and use it to modify the transform component.
- entityUnderNestedPrefab->Init();
- entityUnderNestedPrefab->Activate();
- AZ::TransformBus::Event(entityUnderNestedPrefab->GetId(), &AZ::TransformInterface::SetWorldX, 20.0f);
- GenerateDomAndReloadInstantiatedPrefab(createdPrefab, instantiatedPrefab);
- // Validate that the entity remains in active state throughout the reloading process. This indicates that it is untouched.
- ValidateEntityState(instantiatedPrefab, "EntityUnderParentPrefab", AZ::Entity::State::Active);
- instantiatedPrefab->GetNestedInstances(
- [](AZStd::unique_ptr<Instance>& nestedInstance)
- {
- ValidateEntityState(nestedInstance, "EntityUnderNestedPrefab", AZ::Entity::State::Constructed);
- });
- }
- TEST_F(InstanceDeserializationTest, ReloadInstanceWithoutReloadingNestedInstances)
- {
- AZ::Entity* entityUnderParentPrefab = CreateEntity("EntityUnderParentPrefab", false);
- AZ::Entity* entityUnderNestedPrefab = CreateEntity("EntityUnderNestedPrefab", false);
- entityUnderParentPrefab->CreateComponent(AZ::EditorTransformComponentTypeId);
- InstanceUniquePointer nestedInstanceToUseForCreation =
- m_prefabSystemComponent->CreatePrefab(AzToolsFramework::EntityList{ entityUnderNestedPrefab }, {}, "test/nestedPrefabPath");
- // Extract the template id from the instance and store it in a variable before moving the instance.
- TemplateId nestedPrefabTemplateId = nestedInstanceToUseForCreation->GetTemplateId();
- AZStd::vector<InstanceUniquePointer> nestedInstances;
- nestedInstances.emplace_back(AZStd::move(nestedInstanceToUseForCreation));
- AZStd::pair<InstanceUniquePointer, InstanceUniquePointer> prefabInstances = SetupPrefabInstances(
- AzToolsFramework::EntityList{ entityUnderParentPrefab }, AZStd::move(nestedInstances), m_prefabSystemComponent);
- InstanceUniquePointer createdPrefab = AZStd::move(prefabInstances.first);
- InstanceUniquePointer instantiatedPrefab = AZStd::move(prefabInstances.second);
- ASSERT_EQ(instantiatedPrefab->GetNestedInstanceAliases(nestedPrefabTemplateId).size(), 1);
- // Activate the entity to access the transform interface and use it to modify the transform component.
- entityUnderParentPrefab->Init();
- entityUnderParentPrefab->Activate();
- AZ::TransformBus::Event(entityUnderParentPrefab->GetId(), &AZ::TransformInterface::SetWorldX, 20.0f);
- GenerateDomAndReloadInstantiatedPrefab(createdPrefab, instantiatedPrefab);
- // Validate that the entity under the parent prefab got reloaded.
- ValidateEntityState(instantiatedPrefab, "EntityUnderParentPrefab", AZ::Entity::State::Constructed);
- instantiatedPrefab->GetNestedInstances(
- [](AZStd::unique_ptr<Instance>& nestedInstance)
- {
- // Validate that the entity under the nested prefab remained untouched.
- ValidateEntityState(nestedInstance, "EntityUnderNestedPrefab", AZ::Entity::State::Active);
- });
- }
- } // namespace UnitTest
|