Fix reparenting inside the nested prefabs when using multiple instanced of the nested prefab in PrefabManager

#690
This commit is contained in:
Wojtek Figat
2022-07-27 09:33:01 +02:00
parent 163704085a
commit 1ef8bb723c
4 changed files with 148 additions and 2 deletions

View File

@@ -119,6 +119,126 @@ TEST_CASE("Prefabs")
REQUIRE(instanceA->Children[0]->Children[0]->Children[0]->GetName() == TEXT("Prefab B.Child"));
REQUIRE(instanceA->Children[0]->Children[0]->Children[0]->GetChildrenCount() == 0);
// Cleanup
instanceA->DeleteObject();
instanceB->DeleteObject();
Content::DeleteAsset(prefabA);
Content::DeleteAsset(prefabB);
}
SECTION("Test Adding Object in Nested Prefab")
{
// https://github.com/FlaxEngine/FlaxEngine/issues/690
// Create Prefab B with just root object
AssetReference<Prefab> prefabB = Content::CreateVirtualAsset<Prefab>();
REQUIRE(prefabB);
Guid id;
Guid::Parse("25dbe4b0416be0777a6ce59e8788b10f", id);
prefabB->ChangeID(id);
auto prefabBInit = prefabB->Init(Prefab::TypeName,
"["
"{"
"\"ID\": \"aac6b9644492fbca1a6ab0a7904a557e\","
"\"TypeName\": \"FlaxEngine.EmptyActor\","
"\"Name\": \"Prefab B.Root\""
"}"
"]");
REQUIRE(!prefabBInit);
// Create Prefab A with two nested Prefab B attached to the root
AssetReference<Prefab> prefabA = Content::CreateVirtualAsset<Prefab>();
REQUIRE(prefabA);
Guid::Parse("4cb744714f746e31855f41815612d14b", id);
prefabA->ChangeID(id);
auto prefabAInit = prefabA->Init(Prefab::TypeName,
"["
"{"
"\"ID\": \"244274a04cc60d56a2f024bfeef5772d\","
"\"TypeName\": \"FlaxEngine.EmptyActor\","
"\"Name\": \"Prefab A.Root\""
"},"
"{"
"\"ID\": \"1e51f1094f430733333f8280e78dfcc3\","
"\"PrefabID\": \"25dbe4b0416be0777a6ce59e8788b10f\","
"\"PrefabObjectID\": \"aac6b9644492fbca1a6ab0a7904a557e\","
"\"ParentID\": \"244274a04cc60d56a2f024bfeef5772d\""
"},"
"{"
"\"ID\": \"2e1f2bae4aaedeab8725908ce1aec325\","
"\"PrefabID\": \"25dbe4b0416be0777a6ce59e8788b10f\","
"\"PrefabObjectID\": \"aac6b9644492fbca1a6ab0a7904a557e\","
"\"ParentID\": \"244274a04cc60d56a2f024bfeef5772d\""
"}"
"]");
REQUIRE(!prefabAInit);
// Spawn test instances of both prefabs
ScriptingObjectReference<Actor> instanceB = PrefabManager::SpawnPrefab(prefabB);
ScriptingObjectReference<Actor> instanceA = PrefabManager::SpawnPrefab(prefabA);
// Verify initial scenario
REQUIRE(instanceA);
REQUIRE(instanceB);
REQUIRE(instanceA->GetName() == TEXT("Prefab A.Root"));
REQUIRE(instanceA->GetChildrenCount() == 2);
REQUIRE(instanceA->Children[0]->GetName() == TEXT("Prefab B.Root"));
REQUIRE(instanceA->Children[0]->GetChildrenCount() == 0);
REQUIRE(instanceA->Children[1]->GetName() == TEXT("Prefab B.Root"));
REQUIRE(instanceA->Children[1]->GetChildrenCount() == 0);
// Modify Prefab B instance to add a new actor as a child so at appears in both nested instances in Prefab A instance
Guid newChildId;
Guid::Parse(TEXT("123456a04cc60d56a2f024bfeef57723"), newChildId);
auto newChild = EmptyActor::Spawn(ScriptingObject::SpawnParams(newChildId, EmptyActor::TypeInitializer));
newChild->SetName(TEXT("Prefab B.Child"));
newChild->SetParent(instanceB);
// Apply nested prefab changes
auto applyResult = PrefabManager::ApplyAll(instanceB);
REQUIRE(!applyResult);
// Verify if instance of Prefab B nested instances in instance of Prefab A was properly updated
REQUIRE(instanceA);
REQUIRE(instanceB);
REQUIRE(instanceA->GetName() == TEXT("Prefab A.Root"));
REQUIRE(instanceA->GetChildrenCount() == 2);
REQUIRE(instanceA->Children[0]->GetName() == TEXT("Prefab B.Root"));
REQUIRE(instanceA->Children[0]->GetChildrenCount() == 1);
REQUIRE(instanceA->Children[0]->Children[0]->GetName() == TEXT("Prefab B.Child"));
REQUIRE(instanceA->Children[0]->Children[0]->GetChildrenCount() == 0);
REQUIRE(instanceA->Children[1]->GetName() == TEXT("Prefab B.Root"));
REQUIRE(instanceA->Children[1]->GetChildrenCount() == 1);
REQUIRE(instanceA->Children[1]->Children[0]->GetName() == TEXT("Prefab B.Child"));
REQUIRE(instanceA->Children[1]->Children[0]->GetChildrenCount() == 0);
// Add another child
Guid::Parse(TEXT("678906a04cc60d56a2f024bfeef57723"), newChildId);
newChild = EmptyActor::Spawn(ScriptingObject::SpawnParams(newChildId, EmptyActor::TypeInitializer));
newChild->SetName(TEXT("Prefab B.Child 2"));
newChild->SetParent(instanceB);
// Apply nested prefab changes
applyResult = PrefabManager::ApplyAll(instanceB);
REQUIRE(!applyResult);
// Reparent another child into the first child
newChild->SetParent(instanceB->Children[0]);
// Apply nested prefab changes
applyResult = PrefabManager::ApplyAll(instanceB);
REQUIRE(!applyResult);
// Verify if instance of Prefab B nested instances in instance of Prefab A was properly updated
REQUIRE(instanceA);
REQUIRE(instanceB);
REQUIRE(instanceA->GetChildrenCount() == 2);
REQUIRE(instanceA->Children[0]->GetChildrenCount() == 1);
REQUIRE(instanceA->Children[0]->Children[0]->GetChildrenCount() == 1);
REQUIRE(instanceA->Children[0]->Children[0]->Children[0]->GetChildrenCount() == 0);
REQUIRE(instanceA->Children[1]->GetChildrenCount() == 1);
REQUIRE(instanceA->Children[1]->Children[0]->GetChildrenCount() == 1);
REQUIRE(instanceA->Children[1]->Children[0]->Children[0]->GetChildrenCount() == 0);
// Cleanup
instanceA->DeleteObject();
instanceB->DeleteObject();