NetworkTransformComponent replicates local transform for child entities
+ NetworkTransformComponent replicates world transform for parent entities + NetworkTransformComponent replicates local transform for child entities + Server-side and client-side unittests
This commit is contained in:
@@ -50,7 +50,7 @@ namespace Multiplayer
|
||||
void OnDeactivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
|
||||
|
||||
private:
|
||||
void OnTransformChangedEvent(const AZ::Transform& worldTm);
|
||||
void OnTransformChangedEvent(const AZ::Transform& localTm, const AZ::Transform& worldTm);
|
||||
void OnParentIdChangedEvent(AZ::EntityId oldParent, AZ::EntityId newParent);
|
||||
|
||||
AZ::TransformChangedEvent::Handler m_transformChangedHandler;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
void NetworkTransformComponent::NetworkTransformComponent::Reflect(AZ::ReflectContext* context)
|
||||
void NetworkTransformComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serializeContext)
|
||||
@@ -43,6 +43,11 @@ namespace Multiplayer
|
||||
GetNetBindComponent()->AddEntityPreRenderEventHandler(m_entityPreRenderEventHandler);
|
||||
GetNetBindComponent()->AddEntityCorrectionEventHandler(m_entityCorrectionEventHandler);
|
||||
ParentEntityIdAddEvent(m_parentChangedEventHandler);
|
||||
|
||||
if (!HasController())
|
||||
{
|
||||
OnParentChanged(GetParentEntityId());
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkTransformComponent::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
|
||||
@@ -77,9 +82,20 @@ namespace Multiplayer
|
||||
}
|
||||
}
|
||||
|
||||
if (!GetTransformComponent()->GetWorldTM().IsClose(blendTransform))
|
||||
AzFramework::TransformComponent* transformComponent = GetTransformComponent();
|
||||
if (GetParentEntityId() == InvalidNetEntityId)
|
||||
{
|
||||
GetTransformComponent()->SetWorldTM(blendTransform);
|
||||
if (!transformComponent->GetWorldTM().IsClose(blendTransform))
|
||||
{
|
||||
transformComponent->SetWorldTM(blendTransform);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!transformComponent->GetLocalTM().IsClose(blendTransform))
|
||||
{
|
||||
transformComponent->SetLocalTM(blendTransform);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,31 +109,45 @@ namespace Multiplayer
|
||||
targetTransform.SetUniformScale(GetScale());
|
||||
|
||||
// Hard set the entities transform
|
||||
if (!GetTransformComponent()->GetWorldTM().IsClose(targetTransform))
|
||||
AzFramework::TransformComponent* transformComponent = GetTransformComponent();
|
||||
if (GetParentEntityId() == InvalidNetEntityId)
|
||||
{
|
||||
GetTransformComponent()->SetWorldTM(targetTransform);
|
||||
if (!transformComponent->GetWorldTM().IsClose(targetTransform))
|
||||
{
|
||||
transformComponent->SetWorldTM(targetTransform);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!transformComponent->GetLocalTM().IsClose(targetTransform))
|
||||
{
|
||||
transformComponent->SetLocalTM(targetTransform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkTransformComponent::OnParentChanged(NetEntityId parentId)
|
||||
{
|
||||
const ConstNetworkEntityHandle parentEntityHandle = GetNetworkEntityManager()->GetEntity(parentId);
|
||||
if (parentEntityHandle.Exists())
|
||||
if (AZ::TransformInterface* transformComponent = GetEntity()->GetTransform())
|
||||
{
|
||||
if (const AZ::Entity* parentEntity = parentEntityHandle.GetEntity())
|
||||
const ConstNetworkEntityHandle parentEntityHandle = GetNetworkEntityManager()->GetEntity(parentId);
|
||||
if (parentEntityHandle.Exists())
|
||||
{
|
||||
GetEntity()->GetTransform()->SetParent(parentEntity->GetId());
|
||||
if (const AZ::Entity* parentEntity = parentEntityHandle.GetEntity())
|
||||
{
|
||||
transformComponent->SetParent(parentEntity->GetId());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
transformComponent->SetParent(AZ::EntityId());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GetEntity()->GetTransform()->SetParent(AZ::EntityId());
|
||||
}
|
||||
}
|
||||
|
||||
NetworkTransformComponentController::NetworkTransformComponentController(NetworkTransformComponent& parent)
|
||||
: NetworkTransformComponentControllerBase(parent)
|
||||
, m_transformChangedHandler([this](const AZ::Transform&, const AZ::Transform& worldTm) { OnTransformChangedEvent(worldTm); })
|
||||
, m_transformChangedHandler([this](const AZ::Transform& localTm, const AZ::Transform& worldTm) { OnTransformChangedEvent(localTm, worldTm); })
|
||||
, m_parentIdChangedHandler([this](AZ::EntityId oldParent, AZ::EntityId newParent) { OnParentIdChangedEvent(oldParent, newParent); })
|
||||
{
|
||||
;
|
||||
@@ -125,11 +155,14 @@ namespace Multiplayer
|
||||
|
||||
void NetworkTransformComponentController::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
|
||||
{
|
||||
GetParent().GetTransformComponent()->BindTransformChangedEventHandler(m_transformChangedHandler);
|
||||
OnTransformChangedEvent(GetParent().GetTransformComponent()->GetWorldTM());
|
||||
if (AzFramework::TransformComponent* parentTransform = GetParent().GetTransformComponent())
|
||||
{
|
||||
parentTransform->BindTransformChangedEventHandler(m_transformChangedHandler);
|
||||
OnTransformChangedEvent(parentTransform->GetLocalTM(), parentTransform->GetWorldTM());
|
||||
|
||||
GetParent().GetTransformComponent()->BindParentChangedEventHandler(m_parentIdChangedHandler);
|
||||
OnParentIdChangedEvent(AZ::EntityId(), GetParent().GetTransformComponent()->GetParentId());
|
||||
parentTransform->BindParentChangedEventHandler(m_parentIdChangedHandler);
|
||||
OnParentIdChangedEvent(AZ::EntityId(), parentTransform->GetParentId());
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkTransformComponentController::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
|
||||
@@ -137,11 +170,12 @@ namespace Multiplayer
|
||||
;
|
||||
}
|
||||
|
||||
void NetworkTransformComponentController::OnTransformChangedEvent(const AZ::Transform& worldTm)
|
||||
void NetworkTransformComponentController::OnTransformChangedEvent(const AZ::Transform& localTm, const AZ::Transform& worldTm)
|
||||
{
|
||||
SetRotation(worldTm.GetRotation());
|
||||
SetTranslation(worldTm.GetTranslation());
|
||||
SetScale(worldTm.GetUniformScale());
|
||||
const AZ::Transform& localOrWorld = GetParentEntityId() == InvalidNetEntityId ? worldTm : localTm;
|
||||
SetRotation(localOrWorld.GetRotation());
|
||||
SetTranslation(localOrWorld.GetTranslation());
|
||||
SetScale(localOrWorld.GetUniformScale());
|
||||
}
|
||||
|
||||
void NetworkTransformComponentController::OnParentIdChangedEvent([[maybe_unused]] AZ::EntityId oldParent, AZ::EntityId newParent)
|
||||
@@ -150,7 +184,10 @@ namespace Multiplayer
|
||||
if (parentEntity)
|
||||
{
|
||||
const ConstNetworkEntityHandle parentHandle(parentEntity, GetNetworkEntityTracker());
|
||||
SetParentEntityId(parentHandle.GetNetEntityId());
|
||||
if (parentHandle.Exists())
|
||||
{
|
||||
SetParentEntityId(parentHandle.GetNetEntityId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <MockInterfaces.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Console/Console.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/Name/Name.h>
|
||||
#include <AzCore/Name/NameDictionary.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
@@ -248,17 +249,19 @@ namespace Multiplayer
|
||||
|
||||
void SetupEntity(const AZStd::unique_ptr<AZ::Entity>& entity, NetEntityId netId, NetEntityRole role)
|
||||
{
|
||||
const auto netBindComponent = entity->FindComponent<Multiplayer::NetBindComponent>();
|
||||
EXPECT_NE(netBindComponent, nullptr);
|
||||
netBindComponent->PreInit(entity.get(), PrefabEntityId{ AZ::Name("test"), 1 }, netId, role);
|
||||
entity->Init();
|
||||
if (const auto netBindComponent = entity->FindComponent<Multiplayer::NetBindComponent>())
|
||||
{
|
||||
netBindComponent->PreInit(entity.get(), PrefabEntityId{ AZ::Name("test"), 1 }, netId, role);
|
||||
entity->Init();
|
||||
}
|
||||
}
|
||||
|
||||
static void StopEntity(const AZStd::unique_ptr<AZ::Entity>& entity)
|
||||
{
|
||||
const auto netBindComponent = entity->FindComponent<Multiplayer::NetBindComponent>();
|
||||
EXPECT_NE(netBindComponent, nullptr);
|
||||
netBindComponent->StopEntity();
|
||||
if (const auto netBindComponent = entity->FindComponent<Multiplayer::NetBindComponent>())
|
||||
{
|
||||
netBindComponent->StopEntity();
|
||||
}
|
||||
}
|
||||
|
||||
static void StopAndDeactivateEntity(AZStd::unique_ptr<AZ::Entity>& entity)
|
||||
@@ -311,6 +314,29 @@ namespace Multiplayer
|
||||
entity->FindComponent<NetworkTransformComponent>()->NotifyStateDeltaChanges(notifyRecord);
|
||||
}
|
||||
|
||||
void SetTranslationOnNetworkTransform(const AZStd::unique_ptr<AZ::Entity>& entity, AZ::Vector3 translation)
|
||||
{
|
||||
/* Derived from NetworkTransformComponent.AutoComponent.xml */
|
||||
constexpr int totalBits = 6 /*NetworkTransformComponentInternal::AuthorityToClientDirtyEnum::Count*/;
|
||||
constexpr int translationBit = 1 /*NetworkTransformComponentInternal::AuthorityToClientDirtyEnum::translation_DirtyFlag*/;
|
||||
|
||||
ReplicationRecord currentRecord;
|
||||
currentRecord.m_authorityToClient.AddBits(totalBits);
|
||||
currentRecord.m_authorityToClient.SetBit(translationBit, true);
|
||||
|
||||
constexpr uint32_t bufferSize = 100;
|
||||
AZStd::array<uint8_t, bufferSize> buffer = {};
|
||||
NetworkInputSerializer inSerializer(buffer.begin(), bufferSize);
|
||||
static_cast<ISerializer*>(&inSerializer)->Serialize(translation,
|
||||
"translation" /* Derived from NetworkTransformComponent.AutoComponent.xml */);
|
||||
|
||||
NetworkOutputSerializer outSerializer(buffer.begin(), bufferSize);
|
||||
|
||||
ReplicationRecord notifyRecord = currentRecord;
|
||||
entity->FindComponent<NetworkTransformComponent>()->SerializeStateDeltaMessage(currentRecord, outSerializer);
|
||||
entity->FindComponent<NetworkTransformComponent>()->NotifyStateDeltaChanges(notifyRecord);
|
||||
}
|
||||
|
||||
template <typename Component>
|
||||
void SetHierarchyRootFieldOnNetworkHierarchyChild(const AZStd::unique_ptr<AZ::Entity>& entity, NetEntityId value)
|
||||
{
|
||||
|
||||
@@ -95,8 +95,9 @@ namespace UnitTest
|
||||
|
||||
TEST_F(MultiplayerSystemTests, TestConnectionDatum)
|
||||
{
|
||||
IMultiplayerConnectionMock connMock1 = IMultiplayerConnectionMock(aznumeric_cast<AzNetworking::ConnectionId>(10), AzNetworking::IpAddress(), AzNetworking::ConnectionRole::Acceptor);
|
||||
IMultiplayerConnectionMock connMock2 = IMultiplayerConnectionMock(aznumeric_cast<AzNetworking::ConnectionId>(15), AzNetworking::IpAddress(), AzNetworking::ConnectionRole::Acceptor);
|
||||
using namespace testing;
|
||||
NiceMock<IMultiplayerConnectionMock> connMock1(aznumeric_cast<AzNetworking::ConnectionId>(10), AzNetworking::IpAddress(), AzNetworking::ConnectionRole::Acceptor);
|
||||
NiceMock<IMultiplayerConnectionMock> connMock2(aznumeric_cast<AzNetworking::ConnectionId>(15), AzNetworking::IpAddress(), AzNetworking::ConnectionRole::Acceptor);
|
||||
m_mpComponent->OnConnect(&connMock1);
|
||||
m_mpComponent->OnConnect(&connMock2);
|
||||
|
||||
|
||||
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* 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 <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)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,14 @@
|
||||
#
|
||||
|
||||
set(FILES
|
||||
Tests/Main.cpp
|
||||
Tests/MockInterfaces.h
|
||||
Tests/ClientHierarchyTests.cpp
|
||||
Tests/ServerHierarchyTests.cpp
|
||||
Tests/CommonHierarchySetup.h
|
||||
Tests/IMultiplayerConnectionMock.h
|
||||
Tests/Main.cpp
|
||||
Tests/MockInterfaces.h
|
||||
Tests/MultiplayerSystemTests.cpp
|
||||
Tests/NetworkTransformTests.cpp
|
||||
Tests/RewindableContainerTests.cpp
|
||||
Tests/RewindableObjectTests.cpp
|
||||
Tests/ServerHierarchyTests.cpp
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user