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/NetworkTransformTests.cpp

321 lines
12 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/UnitTest/TestTypes.h>
#include <AzCore/UnitTest/UnitTest.h>
#include <AzFramework/Components/TransformComponent.h>
#include <AzTest/AzTest.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <Multiplayer/NetworkEntity/EntityReplication/EntityReplicator.h>
namespace Multiplayer
{
using namespace testing;
using namespace ::UnitTest;
/*
* (Networked) Parent -> (Networked) Child
*/
class ServerNetTransformTests : 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);
CreateNetworkParentChild(*m_root, *m_child);
AZ::Transform rootTransform = AZ::Transform::CreateIdentity();
rootTransform.SetTranslation(AZ::Vector3::CreateOne());
m_root->m_entity->FindComponent<AzFramework::TransformComponent>()->SetWorldTM(rootTransform);
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetWorldTM(rootTransform);
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(m_root->m_entity->GetId());
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetLocalTM(AZ::Transform::CreateIdentity());
AZ::EntityBus::Broadcast(&AZ::EntityBus::Events::OnEntityActivated, m_root->m_entity->GetId());
MultiplayerTick();
}
void TearDown() override
{
m_child.reset();
m_root.reset();
HierarchyTests::TearDown();
}
void PopulateNetworkEntity(const EntityInfo& entityInfo)
{
entityInfo.m_entity->CreateComponent<AzFramework::TransformComponent>();
entityInfo.m_entity->CreateComponent<NetBindComponent>();
entityInfo.m_entity->CreateComponent<NetworkTransformComponent>();
}
void CreateNetworkParentChild(EntityInfo& root, EntityInfo& child)
{
PopulateNetworkEntity(root);
SetupEntity(root.m_entity, root.m_netId, NetEntityRole::Authority);
PopulateNetworkEntity(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;
void MultiplayerTick()
{
m_root->m_entity->FindComponent<NetBindComponent>()->NotifyPreRender(0.1f);
m_child->m_entity->FindComponent<NetBindComponent>()->NotifyPreRender(0.1f);
}
};
TEST_F(ServerNetTransformTests, SanityCheck)
{
EXPECT_EQ(
m_root->m_entity->FindComponent<AzFramework::TransformComponent>()->GetWorldTM().GetTranslation(),
AZ::Vector3::CreateOne()
);
EXPECT_EQ(
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->GetWorldTM().GetTranslation(),
AZ::Vector3::CreateOne()
);
EXPECT_EQ(
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->GetLocalTM().GetTranslation(),
AZ::Vector3::CreateZero()
);
}
TEST_F(ServerNetTransformTests, NetTransformSavesLocalTransformWhenParentSet)
{
EXPECT_EQ(
m_child->m_entity->FindComponent<NetworkTransformComponent>()->GetTranslation(),
AZ::Vector3::CreateZero()
);
}
TEST_F(ServerNetTransformTests, NetTransformSavesWorldTransformWhenParentIsNotSet)
{
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->SetParent(AZ::EntityId());
MultiplayerTick();
EXPECT_EQ(
m_child->m_entity->FindComponent<NetworkTransformComponent>()->GetTranslation(),
AZ::Vector3::CreateOne() // back at the parent translation
);
}
TEST_F(ServerNetTransformTests, ParentMovesChildNetTransformDoesntChange)
{
EXPECT_EQ(
m_child->m_entity->FindComponent<NetworkTransformComponent>()->GetTranslation(),
AZ::Vector3::CreateZero()
);
// move the parent
AZ::Transform rootTransform = AZ::Transform::CreateIdentity();
rootTransform.SetTranslation(AZ::Vector3::CreateOne() * 10.f);
m_root->m_entity->FindComponent<AzFramework::TransformComponent>()->SetWorldTM(rootTransform);
MultiplayerTick();
EXPECT_EQ(
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->GetWorldTM().GetTranslation(),
AZ::Vector3::CreateOne() * 10.f
);
// child local tm doesn't change
EXPECT_EQ(
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->GetLocalTM().GetTranslation(),
AZ::Vector3::CreateZero()
);
EXPECT_EQ(
m_child->m_entity->FindComponent<NetworkTransformComponent>()->GetTranslation(),
AZ::Vector3::CreateZero()
);
}
/*
* (Networked) Parent -> (Networked) Child
*/
class ClientNetTransformTests : 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);
CreateNetworkParentChild(*m_root, *m_child);
}
void TearDown() override
{
m_child.reset();
m_root.reset();
HierarchyTests::TearDown();
}
void PopulateNetworkEntity(const EntityInfo& entityInfo)
{
entityInfo.m_entity->CreateComponent<AzFramework::TransformComponent>();
entityInfo.m_entity->CreateComponent<NetBindComponent>();
entityInfo.m_entity->CreateComponent<NetworkTransformComponent>();
}
void CreateNetworkParentChild(EntityInfo& root, EntityInfo& child)
{
PopulateNetworkEntity(root);
SetupEntity(root.m_entity, root.m_netId, NetEntityRole::Client);
PopulateNetworkEntity(child);
SetupEntity(child.m_entity, child.m_netId, NetEntityRole::Client);
// 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::Authority, 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::Authority, rootHandle);
root.m_replicator->Initialize(rootHandle);
}
AZStd::unique_ptr<EntityInfo> m_root;
AZStd::unique_ptr<EntityInfo> m_child;
void MultiplayerTick()
{
m_root->m_entity->FindComponent<NetBindComponent>()->NotifyPreRender(0.1f);
m_child->m_entity->FindComponent<NetBindComponent>()->NotifyPreRender(0.1f);
}
};
TEST_F(ClientNetTransformTests, ClientSetsLocalTmWhenParentIsSet)
{
m_root->m_entity->Activate();
m_child->m_entity->Activate();
SetTranslationOnNetworkTransform(m_root->m_entity, AZ::Vector3::CreateOne());
SetParentIdOnNetworkTransform(m_child->m_entity, NetEntityId{ 1 });
SetTranslationOnNetworkTransform(m_child->m_entity, AZ::Vector3::CreateZero());
AZ::EntityBus::Broadcast(&AZ::EntityBus::Events::OnEntityActivated, m_root->m_entity->GetId());
MultiplayerTick();
EXPECT_EQ(
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->GetWorldTM().GetTranslation(),
AZ::Vector3::CreateOne()
);
EXPECT_EQ(
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->GetLocalTM().GetTranslation(),
AZ::Vector3::CreateZero()
);
}
TEST_F(ClientNetTransformTests, ClientSetsWorldTmWhenParentIsNotSet)
{
m_root->m_entity->Activate();
m_child->m_entity->Activate();
SetTranslationOnNetworkTransform(m_root->m_entity, AZ::Vector3::CreateOne());
SetTranslationOnNetworkTransform(m_child->m_entity, AZ::Vector3::CreateZero());
AZ::EntityBus::Broadcast(&AZ::EntityBus::Events::OnEntityActivated, m_root->m_entity->GetId());
MultiplayerTick();
EXPECT_EQ(
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->GetWorldTM().GetTranslation(),
AZ::Vector3::CreateZero()
);
EXPECT_EQ(
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->GetLocalTM().GetTranslation(),
AZ::Vector3::CreateZero()
);
}
TEST_F(ClientNetTransformTests, ChildFollowsWhenParentMovesOnServer)
{
m_root->m_entity->Activate();
m_child->m_entity->Activate();
SetTranslationOnNetworkTransform(m_root->m_entity, AZ::Vector3::CreateOne());
SetParentIdOnNetworkTransform(m_child->m_entity, NetEntityId{ 1 });
SetTranslationOnNetworkTransform(m_child->m_entity, AZ::Vector3::CreateZero());
AZ::EntityBus::Broadcast(&AZ::EntityBus::Events::OnEntityActivated, m_root->m_entity->GetId());
MultiplayerTick();
// now parent moves
SetTranslationOnNetworkTransform(m_root->m_entity, AZ::Vector3::CreateOne() * 2.f);
MultiplayerTick();
EXPECT_EQ(
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->GetWorldTM().GetTranslation(),
AZ::Vector3::CreateOne() * 2.f
);
EXPECT_EQ(
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->GetLocalTM().GetTranslation(),
AZ::Vector3::CreateZero()
);
}
TEST_F(ClientNetTransformTests, ChildAttachesToParentIfParentIdIsSetBeforeActivation)
{
m_root->m_entity->Activate();
SetTranslationOnNetworkTransform(m_root->m_entity, AZ::Vector3::CreateOne());
SetParentIdOnNetworkTransform(m_child->m_entity, NetEntityId{ 1 });
SetTranslationOnNetworkTransform(m_child->m_entity, AZ::Vector3::CreateZero());
m_child->m_entity->Activate();
AZ::EntityBus::Broadcast(&AZ::EntityBus::Events::OnEntityActivated, m_root->m_entity->GetId());
MultiplayerTick();
EXPECT_EQ(
m_child->m_entity->FindComponent<AzFramework::TransformComponent>()->GetParentId(),
AZ::EntityId(1)
);
}
}