You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/Multiplayer/Code/Tests/ServerHierarchyTests.cpp

1370 lines
56 KiB
C++

/*
* 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 <CommonHierarchySetup.h>
#include <MockInterfaces.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Console/Console.h>
#include <AzCore/Name/Name.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/UnitTest/UnitTest.h>
#include <AzFramework/Components/TransformComponent.h>
#include <AzTest/AzTest.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <Multiplayer/Components/NetworkHierarchyChildComponent.h>
#include <Multiplayer/Components/NetworkHierarchyRootComponent.h>
#include <Multiplayer/NetworkEntity/EntityReplication/EntityReplicator.h>
namespace Multiplayer
{
using namespace testing;
using namespace ::UnitTest;
/*
* Parent -> Child
*/
class ServerSimpleHierarchyTests : public HierarchyTests
{
public:
void SetUp() override
{
HierarchyTests::SetUp();
m_root = AZStd::make_unique<EntityInfo>(1, "root", NetEntityId{ 1 }, EntityInfo::Role::Root);
m_child = AZStd::make_unique<EntityInfo>(2, "child", NetEntityId{ 2 }, EntityInfo::Role::Child);
CreateSimpleHierarchy(*m_root, *m_child);
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
// now the two entities are under one hierarchy
}
void TearDown() override
{
m_child.reset();
m_root.reset();
HierarchyTests::TearDown();
}
void CreateSimpleHierarchy(EntityInfo& root, EntityInfo& child)
{
PopulateHierarchicalEntity(root);
SetupEntity(root.m_entity, root.m_netId, NetEntityRole::Authority);
PopulateHierarchicalEntity(child);
SetupEntity(child.m_entity, child.m_netId, NetEntityRole::Authority);
// Create an entity replicator for the child entity
const NetworkEntityHandle childHandle(child.m_entity.get(), m_networkEntityTracker.get());
child.m_replicator = AZStd::make_unique<EntityReplicator>(*m_entityReplicationManager, m_mockConnection.get(), NetEntityRole::Client, childHandle);
child.m_replicator->Initialize(childHandle);
// Create an entity replicator for the root entity
const NetworkEntityHandle rootHandle(root.m_entity.get(), m_networkEntityTracker.get());
root.m_replicator = AZStd::make_unique<EntityReplicator>(*m_entityReplicationManager, m_mockConnection.get(), NetEntityRole::Client, rootHandle);
root.m_replicator->Initialize(rootHandle);
root.m_entity->Activate();
child.m_entity->Activate();
}
AZStd::unique_ptr<EntityInfo> m_root;
AZStd::unique_ptr<EntityInfo> m_child;
};
TEST_F(ServerSimpleHierarchyTests, Server_Sets_Appropriate_Network_Fields_For_Clients)
{
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchyRoot(),
InvalidNetEntityId
);
EXPECT_EQ(
m_child->m_entity->FindComponent<NetworkHierarchyChildComponent>()->GetHierarchyRoot(),
NetEntityId{ 1 }
);
}
TEST_F(ServerSimpleHierarchyTests, Root_Is_Top_Level_Root)
{
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->IsHierarchicalChild(),
false
);
}
TEST_F(ServerSimpleHierarchyTests, Child_Has_Root_Set)
{
EXPECT_EQ(
m_child->m_entity->FindComponent<NetworkHierarchyChildComponent>()->GetHierarchyRoot(),
NetEntityId{ 1 }
);
}
TEST_F(ServerSimpleHierarchyTests, Child_Has_Root_Cleared_On_Detach)
{
// now detach the child
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
EXPECT_EQ(
m_child->m_entity->FindComponent<NetworkHierarchyChildComponent>()->GetHierarchyRoot(),
InvalidNetEntityId
);
}
TEST_F(ServerSimpleHierarchyTests, Root_Has_Child_Reference)
{
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
2
);
}
TEST_F(ServerSimpleHierarchyTests, Root_Has_Child_References_Removed_On_Detach)
{
// now detach the child
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
1
);
}
TEST_F(ServerSimpleHierarchyTests, Root_Deactivates_Child_Has_No_References_To_Root)
{
StopEntity(m_root->m_entity);
m_root->m_entity->Deactivate();
m_root->m_entity.reset();
EXPECT_EQ(
m_child->m_entity->FindComponent<NetworkHierarchyChildComponent>()->GetHierarchyRoot(),
InvalidNetEntityId
);
}
TEST_F(ServerSimpleHierarchyTests, Child_Deactivates_Root_Has_No_References_To_Child)
{
m_child.reset();
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
1
);
}
TEST_F(ServerSimpleHierarchyTests, Root_Deactivates_IsHierarchyEnabled_Is_False)
{
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->IsHierarchyEnabled(),
true
);
StopEntity(m_root->m_entity);
m_root->m_entity->Deactivate();
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->IsHierarchyEnabled(),
false
);
m_root->m_entity.reset();
}
TEST_F(ServerSimpleHierarchyTests, Child_Deactivates_IsHierarchyEnabled_Is_False)
{
EXPECT_EQ(
m_child->m_entity->FindComponent<NetworkHierarchyChildComponent>()->IsHierarchyEnabled(),
true
);
StopEntity(m_child->m_entity);
m_child->m_entity->Deactivate();
EXPECT_EQ(
m_child->m_entity->FindComponent<NetworkHierarchyChildComponent>()->IsHierarchyEnabled(),
false
);
m_child->m_entity.reset();
}
TEST_F(ServerSimpleHierarchyTests, ChildPointsToRootAfterReattachment)
{
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
EXPECT_EQ(
m_child->m_entity->FindComponent<NetworkHierarchyChildComponent>()->GetHierarchyRoot(),
InvalidNetEntityId
);
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
EXPECT_EQ(
m_child->m_entity->FindComponent<NetworkHierarchyChildComponent>()->GetHierarchyRoot(),
m_root->m_entity->FindComponent<NetBindComponent>()->GetNetEntityId()
);
}
TEST_F(ServerSimpleHierarchyTests, ChildHasOwningConnectionIdOfParent)
{
// disconnect and assign new connection ids
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
m_root->m_entity->FindComponent<NetBindComponent>()->SetOwningConnectionId(ConnectionId{ 1 });
m_child->m_entity->FindComponent<NetBindComponent>()->SetOwningConnectionId(ConnectionId{ 2 });
const ConnectionId previousConnectionId = m_child->m_entity->FindComponent<NetBindComponent>()->GetOwningConnectionId();
// re-attach, child's owning connection id should then be root's connection id
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
EXPECT_EQ(
m_child->m_entity->FindComponent<NetBindComponent>()->GetOwningConnectionId(),
m_root->m_entity->FindComponent<NetBindComponent>()->GetOwningConnectionId()
);
// detach, the child should roll back to his previous owning connection id
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
EXPECT_EQ(
m_child->m_entity->FindComponent<NetBindComponent>()->GetOwningConnectionId(),
previousConnectionId
);
}
/*
* Parent -> Child -> ChildOfChild
*/
class ServerDeepHierarchyTests : public HierarchyTests
{
public:
const NetEntityId RootNetEntityId = NetEntityId{ 1 };
const NetEntityId ChildNetEntityId = NetEntityId{ 2 };
const NetEntityId ChildOfChildNetEntityId = NetEntityId{ 3 };
void SetUp() override
{
HierarchyTests::SetUp();
m_root = AZStd::make_unique<EntityInfo>((1), "root", RootNetEntityId, EntityInfo::Role::Root);
m_child = AZStd::make_unique<EntityInfo>((2), "child", ChildNetEntityId, EntityInfo::Role::Child);
m_childOfChild = AZStd::make_unique<EntityInfo>((3), "child of child", ChildOfChildNetEntityId, EntityInfo::Role::Child);
CreateDeepHierarchy(*m_root, *m_child, *m_childOfChild);
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
m_childOfChild->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_child->m_entity->GetId());
// now the entities are under one hierarchy
}
void TearDown() override
{
m_childOfChild.reset();
m_child.reset();
m_root.reset();
HierarchyTests::TearDown();
}
AZStd::unique_ptr<EntityInfo> m_root;
AZStd::unique_ptr<EntityInfo> m_child;
AZStd::unique_ptr<EntityInfo> m_childOfChild;
};
TEST_F(ServerDeepHierarchyTests, Root_Is_Top_Level_Root)
{
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->IsHierarchicalChild(),
false
);
}
TEST_F(ServerDeepHierarchyTests, Root_Has_Child_References)
{
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
3
);
if (m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size() == 3)
{
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[0],
m_root->m_entity.get()
);
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[1],
m_child->m_entity.get()
);
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[2],
m_childOfChild->m_entity.get()
);
}
}
TEST_F(ServerDeepHierarchyTests, Root_Has_Child_Of_Child_Reference_Removed_On_Detach)
{
m_childOfChild->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
2
);
}
TEST_F(ServerDeepHierarchyTests, Root_Has_All_References_Removed_On_Detach_Of_Mid_Child)
{
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
1
);
}
TEST_F(ServerDeepHierarchyTests, Root_Has_All_References_If_Mid_Child_Added_With_Child)
{
m_root->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
// reconnect
m_root->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
3
);
}
TEST_F(ServerDeepHierarchyTests, Root_Has_All_References_If_Child_Of_Child_Added)
{
m_childOfChild->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
// reconnect
m_childOfChild->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
3
);
}
TEST_F(ServerDeepHierarchyTests, Child_Of_Child_Points_To_Root_After_Attach)
{
m_childOfChild->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
// reconnect
m_childOfChild->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
EXPECT_EQ(
m_childOfChild->m_entity->FindComponent<NetworkHierarchyChildComponent>()->GetHierarchyRoot(),
RootNetEntityId
);
}
TEST_F(ServerDeepHierarchyTests, All_New_Children_Point_To_Root_If_Mid_Child_Added_With_Child)
{
m_root->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
// reconnect
m_root->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
EXPECT_EQ(
m_child->m_entity->FindComponent<NetworkHierarchyChildComponent>()->GetHierarchyRoot(),
RootNetEntityId
);
EXPECT_EQ(
m_childOfChild->m_entity->FindComponent<NetworkHierarchyChildComponent>()->GetHierarchyRoot(),
RootNetEntityId
);
}
TEST_F(ServerDeepHierarchyTests, Children_Clear_Reference_To_Root_After_Mid_Child_Detached)
{
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
EXPECT_EQ(
m_child->m_entity->FindComponent<NetworkHierarchyChildComponent>()->GetHierarchyRoot(),
InvalidNetEntityId
);
EXPECT_EQ(
m_childOfChild->m_entity->FindComponent<NetworkHierarchyChildComponent>()->GetHierarchyRoot(),
InvalidNetEntityId
);
}
TEST_F(ServerDeepHierarchyTests, Child_Of_Child_Clears_Reference_To_Root_After_Detached)
{
m_childOfChild->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
EXPECT_EQ(
m_childOfChild->m_entity->FindComponent<NetworkHierarchyChildComponent>()->GetHierarchyRoot(),
InvalidNetEntityId
);
}
TEST_F(ServerDeepHierarchyTests, Root_Deactivates_Children_Have_No_References_To_Root)
{
m_root.reset();
EXPECT_EQ(
m_child->m_entity->FindComponent<NetworkHierarchyChildComponent>()->GetHierarchyRoot(),
InvalidNetEntityId
);
EXPECT_EQ(
m_childOfChild->m_entity->FindComponent<NetworkHierarchyChildComponent>()->GetHierarchyRoot(),
InvalidNetEntityId
);
}
TEST_F(ServerDeepHierarchyTests, Child_Of_Child_Deactivates_Root_Removes_References_To_It)
{
m_childOfChild.reset();
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
2
);
}
TEST_F(ServerDeepHierarchyTests, Testing_Limiting_Hierarchy_Maximum_Size)
{
uint32_t currentMaxLimit = 0;
m_console->GetCvarValue<uint32_t>("bg_hierarchyEntityMaxLimit", currentMaxLimit);
m_console->PerformCommand("bg_hierarchyEntityMaxLimit 2");
// remake the hierarchy
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
2
);
m_console->PerformCommand((AZStd::string("bg_hierarchyEntityMaxLimit ") + AZStd::to_string(currentMaxLimit)).c_str());
m_console->GetCvarValue<uint32_t>("bg_hierarchyEntityMaxLimit", currentMaxLimit);
}
TEST_F(ServerDeepHierarchyTests, ReattachMiddleChildRebuildInvokedTwice)
{
MockNetworkHierarchyCallbackHandler mock;
EXPECT_CALL(mock, OnNetworkHierarchyUpdated(m_root->m_entity->GetId())).Times(2);
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->BindNetworkHierarchyChangedEventHandler(mock.m_changedHandler);
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
}
/*
* Parent -> Child -> Child Of Child
* -> Child2 -> Child Of Child2
* -> Child2 Of Child2
*/
class ServerBranchedHierarchyTests : public HierarchyTests
{
public:
const NetEntityId RootNetEntityId = NetEntityId{ 1 };
const NetEntityId ChildNetEntityId = NetEntityId{ 2 };
const NetEntityId ChildOfChildNetEntityId = NetEntityId{ 3 };
const NetEntityId Child2NetEntityId = NetEntityId{ 4 };
const NetEntityId ChildOfChild2NetEntityId = NetEntityId{ 5 };
const NetEntityId Child2OfChild2NetEntityId = NetEntityId{ 6 };
void SetUp() override
{
HierarchyTests::SetUp();
m_root = AZStd::make_unique<EntityInfo>((1), "root", RootNetEntityId, EntityInfo::Role::Root);
m_child = AZStd::make_unique<EntityInfo>((2), "child", ChildNetEntityId, EntityInfo::Role::Child);
m_childOfChild = AZStd::make_unique<EntityInfo>((3), "child of child", ChildOfChildNetEntityId, EntityInfo::Role::Child);
m_child2 = AZStd::make_unique<EntityInfo>((4), "child2", Child2NetEntityId, EntityInfo::Role::Child);
m_childOfChild2 = AZStd::make_unique<EntityInfo>((5), "child of child2", ChildOfChild2NetEntityId, EntityInfo::Role::Child);
m_child2OfChild2 = AZStd::make_unique<EntityInfo>((6), "child2 of child2", Child2OfChild2NetEntityId, EntityInfo::Role::Child);
CreateBranchedHierarchy(*m_root, *m_child, *m_childOfChild,
*m_child2, *m_childOfChild2, *m_child2OfChild2);
m_child2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
m_childOfChild2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_child2->m_entity->GetId());
m_child2OfChild2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_child2->m_entity->GetId());
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
m_childOfChild->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_child->m_entity->GetId());
// now the entities are under one hierarchy
}
void TearDown() override
{
m_child2OfChild2.reset();
m_childOfChild2.reset();
m_child2.reset();
m_childOfChild.reset();
m_child.reset();
m_root.reset();
HierarchyTests::TearDown();
}
void CreateBranchedHierarchy(EntityInfo& root, EntityInfo& child, EntityInfo& childOfChild,
EntityInfo& child2, EntityInfo& childOfChild2, EntityInfo& child2OfChild2)
{
PopulateHierarchicalEntity(root);
PopulateHierarchicalEntity(child);
PopulateHierarchicalEntity(childOfChild);
PopulateHierarchicalEntity(child2);
PopulateHierarchicalEntity(childOfChild2);
PopulateHierarchicalEntity(child2OfChild2);
SetupEntity(root.m_entity, root.m_netId, NetEntityRole::Authority);
SetupEntity(child.m_entity, child.m_netId, NetEntityRole::Authority);
SetupEntity(childOfChild.m_entity, childOfChild.m_netId, NetEntityRole::Authority);
SetupEntity(child2.m_entity, child2.m_netId, NetEntityRole::Authority);
SetupEntity(childOfChild2.m_entity, childOfChild2.m_netId, NetEntityRole::Authority);
SetupEntity(child2OfChild2.m_entity, child2OfChild2.m_netId, NetEntityRole::Authority);
// Create entity replicators
const NetworkEntityHandle childOfChild2Handle(childOfChild2.m_entity.get(), m_networkEntityTracker.get());
childOfChild.m_replicator = AZStd::make_unique<EntityReplicator>(*m_entityReplicationManager, m_mockConnection.get(), NetEntityRole::Client, childOfChild2Handle);
childOfChild.m_replicator->Initialize(childOfChild2Handle);
const NetworkEntityHandle child2OfChild2Handle(child2OfChild2.m_entity.get(), m_networkEntityTracker.get());
childOfChild.m_replicator = AZStd::make_unique<EntityReplicator>(*m_entityReplicationManager, m_mockConnection.get(), NetEntityRole::Client, child2OfChild2Handle);
childOfChild.m_replicator->Initialize(child2OfChild2Handle);
const NetworkEntityHandle child2Handle(child2.m_entity.get(), m_networkEntityTracker.get());
child.m_replicator = AZStd::make_unique<EntityReplicator>(*m_entityReplicationManager, m_mockConnection.get(), NetEntityRole::Client, child2Handle);
child.m_replicator->Initialize(child2Handle);
const NetworkEntityHandle childOfChildHandle(childOfChild.m_entity.get(), m_networkEntityTracker.get());
childOfChild.m_replicator = AZStd::make_unique<EntityReplicator>(*m_entityReplicationManager, m_mockConnection.get(), NetEntityRole::Client, childOfChildHandle);
childOfChild.m_replicator->Initialize(childOfChildHandle);
const NetworkEntityHandle childHandle(child.m_entity.get(), m_networkEntityTracker.get());
child.m_replicator = AZStd::make_unique<EntityReplicator>(*m_entityReplicationManager, m_mockConnection.get(), NetEntityRole::Client, childHandle);
child.m_replicator->Initialize(childHandle);
const NetworkEntityHandle rootHandle(root.m_entity.get(), m_networkEntityTracker.get());
root.m_replicator = AZStd::make_unique<EntityReplicator>(*m_entityReplicationManager, m_mockConnection.get(), NetEntityRole::Client, rootHandle);
root.m_replicator->Initialize(rootHandle);
root.m_entity->Activate();
child.m_entity->Activate();
childOfChild.m_entity->Activate();
child2.m_entity->Activate();
childOfChild2.m_entity->Activate();
child2OfChild2.m_entity->Activate();
}
AZStd::unique_ptr<EntityInfo> m_root;
AZStd::unique_ptr<EntityInfo> m_child;
AZStd::unique_ptr<EntityInfo> m_childOfChild;
AZStd::unique_ptr<EntityInfo> m_child2;
AZStd::unique_ptr<EntityInfo> m_childOfChild2;
AZStd::unique_ptr<EntityInfo> m_child2OfChild2;
};
TEST_F(ServerBranchedHierarchyTests, Sanity_Check)
{
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
6
);
if (m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size() == 6)
{
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[0],
m_root->m_entity.get()
);
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[1],
m_child->m_entity.get()
);
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[2],
m_child2->m_entity.get()
);
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[3],
m_childOfChild->m_entity.get()
);
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[4],
m_child2OfChild2->m_entity.get()
);
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[5],
m_childOfChild2->m_entity.get()
);
}
}
TEST_F(ServerBranchedHierarchyTests, Detach_Child_While_Child2_Remains_Attached)
{
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
4
);
if (m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size() == 4)
{
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[0],
m_root->m_entity.get()
);
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[1],
m_child2->m_entity.get()
);
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[2],
m_child2OfChild2->m_entity.get()
);
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[3],
m_childOfChild2->m_entity.get()
);
}
EXPECT_EQ(
m_child2->m_entity->FindComponent<NetworkHierarchyChildComponent>()->GetHierarchicalRoot(),
m_root->m_entity.get()
);
EXPECT_EQ(
m_child->m_entity->FindComponent<NetworkHierarchyChildComponent>()->GetHierarchicalRoot(),
nullptr
);
EXPECT_EQ(
m_childOfChild->m_entity->FindComponent<NetworkHierarchyChildComponent>()->GetHierarchicalRoot(),
nullptr
);
}
TEST_F(ServerBranchedHierarchyTests, Detach_Child_Then_Attach_To_Child2)
{
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_child2->m_entity->GetId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
6
);
}
/*
* Sets up 2 deep hierarchies.
*/
class ServerHierarchyOfHierarchyTests : public ServerDeepHierarchyTests
{
public:
const NetEntityId Root2NetEntityId = NetEntityId{ 4 };
const NetEntityId Child2NetEntityId = NetEntityId{ 5 };
const NetEntityId ChildOfChild2NetEntityId = NetEntityId{ 6 };
void SetUp() override
{
ServerDeepHierarchyTests::SetUp();
m_root2 = AZStd::make_unique<EntityInfo>((4), "root 2", Root2NetEntityId, EntityInfo::Role::Root);
m_child2 = AZStd::make_unique<EntityInfo>((5), "child 2", Child2NetEntityId, EntityInfo::Role::Child);
m_childOfChild2 = AZStd::make_unique<EntityInfo>((6), "child of child 2", ChildOfChild2NetEntityId, EntityInfo::Role::Child);
CreateDeepHierarchy(*m_root2, *m_child2, *m_childOfChild2);
m_child2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root2->m_entity->GetId());
m_childOfChild2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_child2->m_entity->GetId());
// now the entities are under one hierarchy
}
void TearDown() override
{
m_childOfChild2.reset();
m_child2.reset();
m_root2.reset();
ServerDeepHierarchyTests::TearDown();
}
AZStd::unique_ptr<EntityInfo> m_root2;
AZStd::unique_ptr<EntityInfo> m_child2;
AZStd::unique_ptr<EntityInfo> m_childOfChild2;
};
TEST_F(ServerHierarchyOfHierarchyTests, Hierarchies_Are_Not_Related)
{
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
3
);
if (m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size() == 3)
{
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[0],
m_root->m_entity.get()
);
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[1],
m_child->m_entity.get()
);
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[2],
m_childOfChild->m_entity.get()
);
}
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
3
);
if (m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size() == 3)
{
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[0],
m_root2->m_entity.get()
);
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[1],
m_child2->m_entity.get()
);
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[2],
m_childOfChild2->m_entity.get()
);
}
}
TEST_F(ServerHierarchyOfHierarchyTests, Inner_Root_Is_Not_Top_Level_Root)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->IsHierarchicalChild(),
false
);
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->IsHierarchicalChild(),
true
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Top_Root_References_All_When_Another_Hierarchy_Attached_At_Root)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
6
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Top_Root_References_All_When_Another_Hierarchy_Attached_At_Child)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
6
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Top_Root_References_All_When_Another_Hierarchy_Attached_At_Child_Of_Child)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
6
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Inner_Root_References_Top_Root_When_Another_Hierarchy_Attached_At_Root)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->IsHierarchicalChild(),
true
);
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchyRoot(),
RootNetEntityId
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Inner_Root_References_Top_Root_When_Another_Hierarchy_Attached_At_Child)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->IsHierarchicalChild(),
true
);
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchyRoot(),
RootNetEntityId
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Inner_Root_References_Top_Root_When_Another_Hierarchy_Attached_At_Child_Of_Child)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->IsHierarchicalChild(),
true
);
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchyRoot(),
RootNetEntityId
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Inner_Root_Doesnt_Keep_Child_References)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
0
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Inner_Root_Has_Child_References_After_Detachment_From_Top_Root)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
// detach
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
3
);
if (m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size() == 3)
{
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[0],
m_root2->m_entity.get()
);
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[1],
m_child2->m_entity.get()
);
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities()[2],
m_childOfChild2->m_entity.get()
);
}
}
TEST_F(ServerHierarchyOfHierarchyTests, InnerChildrenPointToInnerRootAfterDetachmentFromTopRoot)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
// detach
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
EXPECT_EQ(
m_child2->m_entity->FindComponent<NetworkHierarchyChildComponent>()->GetHierarchyRoot(),
m_root2->m_entity->FindComponent<NetBindComponent>()->GetNetEntityId()
);
EXPECT_EQ(
m_childOfChild2->m_entity->FindComponent<NetworkHierarchyChildComponent>()->GetHierarchyRoot(),
m_root2->m_entity->FindComponent<NetBindComponent>()->GetNetEntityId()
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Inner_Root_Has_Child_References_After_Detachment_From_Child_Of_Child)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
// detach
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
3
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Inner_Root_Has_Child_References_After_Top_Root_Deactivates)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
m_root.reset();
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
3
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Inner_Root_Has_Child_References_After_Child_Of_Top_Root_Deactivates)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
m_child.reset();
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
3
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Inner_Root_Has_Child_References_After_Child_Of_Child_Deactivates)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
m_childOfChild.reset();
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
3
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Stress_Test_Inner_Root_Has_Child_References_After_Detachment_From_Child_Of_Child)
{
for (int i = 0; i < 100; ++i)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
// detach
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
}
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
3
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Top_Root_Updates_Child_References_After_Detachment_Of_Child_Of_Child_In_Inner_Hierarchy)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
// detach
m_childOfChild2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
5
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Top_Root_Updates_Child_References_After_Attachment_Of_Child_Of_Child_In_Inner_Hierarchy)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
// detach
m_childOfChild2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
// re-connect
m_childOfChild2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_child2->m_entity->GetId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
6
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Top_Root_Updates_Child_References_After_Child_Of_Child_Changed_Hierarchies)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
// detach
m_childOfChild2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
// connect to a different hierarchy
m_childOfChild2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
6
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Top_Root_Updates_Child_References_After_Detachment_Of_Child_In_Inner_Hierarchy)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
// detach
m_child2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
4
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Top_Root_Updates_Child_References_After_Child_Changed_Hierarchies)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
// detach
m_child2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
// connect to a different hierarchy
m_child2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
6
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Inner_Root_Has_No_Child_References_After_All_Children_Moved_To_Another_Hierarchy)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
m_child2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
// detach
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
1
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Inner_Root_Child_Deactivated_Top_Root_Has_No_Child_Reference_To_It)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
m_child2.reset();
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
4
);
}
TEST_F(ServerHierarchyOfHierarchyTests, Testing_Limiting_Hierarchy_Maximum_Size)
{
uint32_t currentMaxLimit = 0;
m_console->GetCvarValue<uint32_t>("bg_hierarchyEntityMaxLimit", currentMaxLimit);
m_console->PerformCommand("bg_hierarchyEntityMaxLimit 2");
// remake the top level hierarchy
m_root->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
m_root->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
2
);
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
2
);
m_console->PerformCommand((AZStd::string("bg_hierarchyEntityMaxLimit ") + AZStd::to_string(currentMaxLimit)).c_str());
m_console->GetCvarValue<uint32_t>("bg_hierarchyEntityMaxLimit", currentMaxLimit);
}
TEST_F(ServerHierarchyOfHierarchyTests, InnerRootAndItsChildrenHaveOwningConnectionIdOfTopRoot)
{
// Assign new connection ids.
m_root->m_entity->FindComponent<NetBindComponent>()->SetOwningConnectionId(ConnectionId{ 1 });
m_root2->m_entity->FindComponent<NetBindComponent>()->SetOwningConnectionId(ConnectionId{ 2 });
// Attach then inner hierarchy's owning connection id should then be top root's connection id.
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetBindComponent>()->GetOwningConnectionId(),
m_root->m_entity->FindComponent<NetBindComponent>()->GetOwningConnectionId()
);
EXPECT_EQ(
m_child2->m_entity->FindComponent<NetBindComponent>()->GetOwningConnectionId(),
m_root->m_entity->FindComponent<NetBindComponent>()->GetOwningConnectionId()
);
EXPECT_EQ(
m_childOfChild2->m_entity->FindComponent<NetBindComponent>()->GetOwningConnectionId(),
m_root->m_entity->FindComponent<NetBindComponent>()->GetOwningConnectionId()
);
}
TEST_F(ServerHierarchyOfHierarchyTests, InnerRootAndItsChildrenHaveTheirOriginalOwningConnectionIdAfterDetachingFromTopRoot)
{
// Assign new connection ids.
m_root->m_entity->FindComponent<NetBindComponent>()->SetOwningConnectionId(ConnectionId{ 1 });
m_root2->m_entity->FindComponent<NetBindComponent>()->SetOwningConnectionId(ConnectionId{ 2 });
// Attach then inner hierarchy's owning connection id should then be top root's connection id.
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
// detach, inner hierarchy should roll back to his previous owning connection id
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetBindComponent>()->GetOwningConnectionId(),
ConnectionId{ 2 }
);
EXPECT_EQ(
m_child2->m_entity->FindComponent<NetBindComponent>()->GetOwningConnectionId(),
m_root2->m_entity->FindComponent<NetBindComponent>()->GetOwningConnectionId()
);
EXPECT_EQ(
m_childOfChild2->m_entity->FindComponent<NetBindComponent>()->GetOwningConnectionId(),
m_root2->m_entity->FindComponent<NetBindComponent>()->GetOwningConnectionId()
);
}
/*
* Parent -> Child -> ChildOfChild (not marked as in a hierarchy)
*/
class ServerMixedDeepHierarchyTests : public HierarchyTests
{
public:
void SetUp() override
{
HierarchyTests::SetUp();
m_root = AZStd::make_unique<EntityInfo>((1), "root", NetEntityId{ 1 }, EntityInfo::Role::Root);
m_child = AZStd::make_unique<EntityInfo>((2), "child", NetEntityId{ 2 }, EntityInfo::Role::Child);
m_childOfChild = AZStd::make_unique<EntityInfo>((3), "child of child", NetEntityId{ 3 }, EntityInfo::Role::None);
CreateDeepHierarchy(*m_root, *m_child, *m_childOfChild);
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
m_childOfChild->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_child->m_entity->GetId());
// now the entities are under one hierarchy
}
void TearDown() override
{
m_childOfChild.reset();
m_child.reset();
m_root.reset();
HierarchyTests::TearDown();
}
AZStd::unique_ptr<EntityInfo> m_root;
AZStd::unique_ptr<EntityInfo> m_child;
AZStd::unique_ptr<EntityInfo> m_childOfChild;
};
TEST_F(ServerMixedDeepHierarchyTests, Top_Root_Ignores_Non_Hierarchical_Entities)
{
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
2
);
}
TEST_F(ServerMixedDeepHierarchyTests, Detaching_Non_Hierarchical_Entity_Has_No_Effect_On_Top_Root)
{
m_childOfChild->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
2
);
}
TEST_F(ServerMixedDeepHierarchyTests, Attaching_Non_Hierarchical_Entity_Has_No_Effect_On_Top_Root)
{
m_childOfChild->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
m_childOfChild->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
2
);
}
/*
* 1st hierarchy: Parent -> Child -> ChildOfChild (not marked as in a hierarchy)
* 2nd hierarchy: Parent2 -> Child2 (not marked as in a hierarchy) -> ChildOfChild2
*/
class ServerMixedHierarchyOfHierarchyTests : public ServerMixedDeepHierarchyTests
{
public:
void SetUp() override
{
ServerMixedDeepHierarchyTests::SetUp();
m_root2 = AZStd::make_unique<EntityInfo>((4), "root 2", NetEntityId{ 4 }, EntityInfo::Role::Root);
m_child2 = AZStd::make_unique<EntityInfo>((5), "child 2", NetEntityId{ 5 }, EntityInfo::Role::None);
m_childOfChild2 = AZStd::make_unique<EntityInfo>((6), "child of child 2", NetEntityId{ 6 }, EntityInfo::Role::Child);
CreateDeepHierarchy(*m_root2, *m_child2, *m_childOfChild2);
m_child2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root2->m_entity->GetId());
m_childOfChild2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_child2->m_entity->GetId());
// now the entities are under one hierarchy
}
void TearDown() override
{
m_childOfChild2.reset();
m_child2.reset();
m_root2.reset();
ServerMixedDeepHierarchyTests::TearDown();
}
AZStd::unique_ptr<EntityInfo> m_root2;
AZStd::unique_ptr<EntityInfo> m_child2;
AZStd::unique_ptr<EntityInfo> m_childOfChild2;
};
TEST_F(ServerMixedHierarchyOfHierarchyTests, Sanity_Check_Ingore_Children_Without_Hierarchy_Components)
{
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
2
);
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
1
);
}
TEST_F(ServerMixedHierarchyOfHierarchyTests, Adding_Mixed_Hierarchy_Ingores_Children_Without_Hierarchy_Components)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
EXPECT_EQ(
m_root->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
3
);
}
TEST_F(ServerMixedHierarchyOfHierarchyTests, Attaching_Hierarchy_To_Non_Hierarchical_Entity_Does_Not_Merge_Hierarchies)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->IsHierarchicalChild(),
false
);
}
/*
* Sets up a hierarchy with 3 roots, 2 of them being inner roots.
*/
class ServerHierarchyWithThreeRoots : public ServerHierarchyOfHierarchyTests
{
public:
const NetEntityId Root3NetEntityId = NetEntityId{ 7 };
const NetEntityId Child3NetEntityId = NetEntityId{ 8 };
const NetEntityId ChildOfChild3NetEntityId = NetEntityId{ 9 };
void SetUp() override
{
ServerHierarchyOfHierarchyTests::SetUp();
m_root3 = AZStd::make_unique<EntityInfo>((7), "root 3", Root3NetEntityId, EntityInfo::Role::Root);
m_child3 = AZStd::make_unique<EntityInfo>((8), "child 3", Child3NetEntityId, EntityInfo::Role::Child);
m_childOfChild3 = AZStd::make_unique<EntityInfo>((9), "child of child 3", ChildOfChild3NetEntityId, EntityInfo::Role::Child);
CreateDeepHierarchy(*m_root3, *m_child3, *m_childOfChild3);
m_child3->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root3->m_entity->GetId());
m_childOfChild3->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_child3->m_entity->GetId());
// now the entities are under one hierarchy
}
void TearDown() override
{
m_childOfChild3.reset();
m_child3.reset();
m_root3.reset();
ServerHierarchyOfHierarchyTests::TearDown();
}
AZStd::unique_ptr<EntityInfo> m_root3;
AZStd::unique_ptr<EntityInfo> m_child3;
AZStd::unique_ptr<EntityInfo> m_childOfChild3;
};
TEST_F(ServerHierarchyWithThreeRoots, Top_Root_Active_Then_Inner_Roots_Have_No_Child_References)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
m_root3->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
0
);
EXPECT_EQ(
m_root3->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
0
);
}
TEST_F(ServerHierarchyWithThreeRoots, Top_Root_Deactivates_Inner_Roots_Have_Child_References)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
m_root3->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
m_root.reset();
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
3
);
EXPECT_EQ(
m_root3->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
3
);
}
TEST_F(ServerHierarchyWithThreeRoots, Child_Of_Top_Root_Deactivates_Inner_Roots_Have_Child_References)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
m_root3->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
m_child.reset();
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
3
);
EXPECT_EQ(
m_root3->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
3
);
}
TEST_F(ServerHierarchyWithThreeRoots, Child_Of_Child_Of_Top_Root_Deactivates_Inner_Roots_Have_Child_References)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
m_root3->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
m_childOfChild.reset();
EXPECT_EQ(
m_root2->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
3
);
EXPECT_EQ(
m_root3->m_entity->FindComponent<NetworkHierarchyRootComponent>()->GetHierarchicalEntities().size(),
3
);
}
TEST_F(ServerHierarchyWithThreeRoots, InnerRootLeftTopRootThenLastChildGetsJoinedEventOnce)
{
m_root2->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
m_root3->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_childOfChild->m_entity->GetId());
MockNetworkHierarchyCallbackHandler mock;
EXPECT_CALL(mock, OnNetworkHierarchyUpdated(m_root3->m_entity->GetId()));
m_childOfChild3->m_entity->FindComponent<NetworkHierarchyChildComponent>()->BindNetworkHierarchyChangedEventHandler(mock.m_changedHandler);
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
}
}