merge from main
This commit is contained in:
@@ -301,4 +301,4 @@ TEST_F(BehaviorEntityTest, GetComponentConfiguration_Succeeds)
|
||||
bool configSuccess = m_behaviorEntity.GetComponentConfiguration(rawComponent->GetId(), retrievedConfig);
|
||||
EXPECT_TRUE(configSuccess);
|
||||
EXPECT_EQ(rawComponent->m_config.m_brimWidth, retrievedConfig.m_brimWidth);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,4 +63,4 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
NAME AZ::Framework.Tests
|
||||
)
|
||||
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzFramework/Viewport/ClickDetector.h>
|
||||
#include <AzFramework/Viewport/ScreenGeometry.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
std::ostream& operator<<(std::ostream& os, const ClickDetector::ClickOutcome clickOutcome)
|
||||
{
|
||||
switch (clickOutcome)
|
||||
{
|
||||
case ClickDetector::ClickOutcome::Click:
|
||||
os << "ClickOutcome::Click";
|
||||
break;
|
||||
case ClickDetector::ClickOutcome::Move:
|
||||
os << "ClickOutcome::Move";
|
||||
break;
|
||||
case ClickDetector::ClickOutcome::Release:
|
||||
os << "ClickOutcome::Release";
|
||||
break;
|
||||
case ClickDetector::ClickOutcome::Nil:
|
||||
os << "ClickOutcome::Nil";
|
||||
break;
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
} // namespace AzFramework
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
using AzFramework::ClickDetector;
|
||||
using AzFramework::ScreenVector;
|
||||
|
||||
class ClickDetectorFixture : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
ClickDetector m_clickDetector;
|
||||
};
|
||||
|
||||
TEST_F(ClickDetectorFixture, ClickIsDetectedWithNoMouseMovementOnMouseUp)
|
||||
{
|
||||
using ::testing::Eq;
|
||||
|
||||
const ClickDetector::ClickOutcome initialDownOutcome =
|
||||
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
|
||||
const ClickDetector::ClickOutcome initialUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0));
|
||||
|
||||
EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil));
|
||||
EXPECT_THAT(initialUpOutcome, Eq(ClickDetector::ClickOutcome::Click));
|
||||
}
|
||||
|
||||
TEST_F(ClickDetectorFixture, MoveIsDetectedWithMouseMovementAfterMouseDown)
|
||||
{
|
||||
using ::testing::Eq;
|
||||
|
||||
const ClickDetector::ClickOutcome initialDownOutcome =
|
||||
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
|
||||
const ClickDetector::ClickOutcome initialMoveOutcome =
|
||||
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(10, 10));
|
||||
|
||||
EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil));
|
||||
EXPECT_THAT(initialMoveOutcome, Eq(ClickDetector::ClickOutcome::Move));
|
||||
}
|
||||
|
||||
TEST_F(ClickDetectorFixture, ReleaseIsDetectedAfterMouseMovementOnMouseUp)
|
||||
{
|
||||
using ::testing::Eq;
|
||||
|
||||
const ClickDetector::ClickOutcome initialDownOutcome =
|
||||
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
|
||||
// move
|
||||
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(10, 10));
|
||||
const ClickDetector::ClickOutcome initialUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0));
|
||||
|
||||
EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil));
|
||||
EXPECT_THAT(initialUpOutcome, Eq(ClickDetector::ClickOutcome::Release));
|
||||
}
|
||||
|
||||
TEST_F(ClickDetectorFixture, MoveIsReturnedOnlyAfterFirstMouseMove)
|
||||
{
|
||||
using ::testing::Eq;
|
||||
|
||||
const ClickDetector::ClickOutcome initialDownOutcome =
|
||||
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
|
||||
const ClickDetector::ClickOutcome initialMoveOutcome =
|
||||
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(10, 10));
|
||||
const ClickDetector::ClickOutcome secondaryMoveOutcome =
|
||||
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(10, 10));
|
||||
|
||||
EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil));
|
||||
EXPECT_THAT(initialMoveOutcome, Eq(ClickDetector::ClickOutcome::Move));
|
||||
EXPECT_THAT(secondaryMoveOutcome, Eq(ClickDetector::ClickOutcome::Nil));
|
||||
}
|
||||
|
||||
TEST_F(ClickDetectorFixture, ClickIsNotRegisteredAfterDoubleClick)
|
||||
{
|
||||
using ::testing::Eq;
|
||||
|
||||
const ClickDetector::ClickOutcome initialDownOutcome =
|
||||
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
|
||||
const ClickDetector::ClickOutcome initialUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0));
|
||||
const ClickDetector::ClickOutcome secondaryDownOutcome =
|
||||
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
|
||||
const ClickDetector::ClickOutcome secondaryUpOutcome =
|
||||
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0));
|
||||
|
||||
EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil));
|
||||
EXPECT_THAT(initialUpOutcome, Eq(ClickDetector::ClickOutcome::Click));
|
||||
EXPECT_THAT(secondaryDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // double click
|
||||
EXPECT_THAT(secondaryUpOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // click not registered
|
||||
}
|
||||
|
||||
TEST_F(ClickDetectorFixture, ClickIsNotRegisteredAfterIgnoredDoubleClick)
|
||||
{
|
||||
using ::testing::Eq;
|
||||
|
||||
const ClickDetector::ClickOutcome initialDownOutcome =
|
||||
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
|
||||
const ClickDetector::ClickOutcome initialUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0));
|
||||
const ClickDetector::ClickOutcome secondaryDownOutcome =
|
||||
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(0, 0));
|
||||
const ClickDetector::ClickOutcome secondaryUpOutcome =
|
||||
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0));
|
||||
|
||||
EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil));
|
||||
EXPECT_THAT(initialUpOutcome, Eq(ClickDetector::ClickOutcome::Click));
|
||||
EXPECT_THAT(secondaryDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // ignored double click
|
||||
EXPECT_THAT(secondaryUpOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // click not registered
|
||||
}
|
||||
} // namespace UnitTest
|
||||
@@ -177,4 +177,4 @@ namespace UnitTest
|
||||
EXPECT_NE(testRuntimeComponent, nullptr);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1100,6 +1100,10 @@ namespace UnitTest
|
||||
void UnregisterComponentDescriptor(const ComponentDescriptor*) override {}
|
||||
void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler&) override {}
|
||||
void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler&) override {}
|
||||
void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override {}
|
||||
void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override {}
|
||||
void SignalEntityActivated(Entity*) override {}
|
||||
void SignalEntityDeactivated(Entity*) override {}
|
||||
bool AddEntity(Entity*) override { return true; }
|
||||
bool RemoveEntity(Entity*) override { return true; }
|
||||
bool DeleteEntity(const EntityId&) override { return true; }
|
||||
@@ -1125,6 +1129,7 @@ namespace UnitTest
|
||||
AllocatorsFixture::SetUp();
|
||||
|
||||
ComponentApplicationBus::Handler::BusConnect();
|
||||
AZ::Interface<AZ::ComponentApplicationRequests>::Register(this);
|
||||
m_serializeContext.reset(aznew AZ::SerializeContext(true, true));
|
||||
|
||||
Entity::Reflect(m_serializeContext.get());
|
||||
@@ -1139,6 +1144,7 @@ namespace UnitTest
|
||||
m_descriptors.set_capacity(0);
|
||||
|
||||
m_serializeContext.reset();
|
||||
AZ::Interface<AZ::ComponentApplicationRequests>::Unregister(this);
|
||||
ComponentApplicationBus::Handler::BusDisconnect();
|
||||
|
||||
AllocatorsFixture::TearDown();
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzFramework/Viewport/CursorState.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
using AzFramework::CursorState;
|
||||
using AzFramework::ScreenVector;
|
||||
using AzFramework::ScreenPoint;
|
||||
|
||||
class CursorStateFixture : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
CursorState m_cursorState;
|
||||
};
|
||||
|
||||
TEST_F(CursorStateFixture, CursorStateHasZeroDeltaInitially)
|
||||
{
|
||||
using ::testing::Eq;
|
||||
EXPECT_THAT(m_cursorState.CursorDelta(), Eq(ScreenVector(0, 0)));
|
||||
}
|
||||
|
||||
TEST_F(CursorStateFixture, CursorStateReturnsZeroDeltaAfterSingleMoveAndUpdate)
|
||||
{
|
||||
using ::testing::Eq;
|
||||
|
||||
m_cursorState.SetCurrentPosition(ScreenPoint(10, 10));
|
||||
m_cursorState.Update();
|
||||
|
||||
EXPECT_THAT(m_cursorState.CursorDelta(), Eq(ScreenVector(0, 0)));
|
||||
}
|
||||
|
||||
TEST_F(CursorStateFixture, CursorStateReturnsDeltaAfterSecondMoveAndUpdate)
|
||||
{
|
||||
using ::testing::Eq;
|
||||
|
||||
m_cursorState.SetCurrentPosition(ScreenPoint(10, 10));
|
||||
m_cursorState.Update();
|
||||
m_cursorState.SetCurrentPosition(ScreenPoint(15, 22));
|
||||
|
||||
EXPECT_THAT(m_cursorState.CursorDelta(), Eq(ScreenVector(5, 12)));
|
||||
}
|
||||
} // namespace UnitTest
|
||||
@@ -83,4 +83,4 @@ namespace UnitTest
|
||||
AZStd::aligned_storage<sizeof(NoUserSettingsApplication), AZStd::alignment_of<NoUserSettingsApplication>::value>::type m_applicationBuffer;
|
||||
AzFramework::Application* m_application;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <GridMate/Session/Session.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class MockSession
|
||||
: public GridMate::GridSession
|
||||
{
|
||||
public:
|
||||
MockSession(GridMate::SessionService* service)
|
||||
: GridSession(service)
|
||||
{
|
||||
}
|
||||
|
||||
void SetReplicaManager(GridMate::ReplicaManager* replicaManager)
|
||||
{
|
||||
m_replicaMgr = replicaManager;
|
||||
}
|
||||
|
||||
MOCK_METHOD4(CreateRemoteMember, GridMate::GridMember*(const GridMate::string&, GridMate::ReadBuffer&, GridMate::RemotePeerMode, GridMate::ConnectionID));
|
||||
MOCK_METHOD1(OnSessionParamChanged, void(const GridMate::GridSessionParam&));
|
||||
MOCK_METHOD1(OnSessionParamRemoved, void(const GridMate::string&));
|
||||
};
|
||||
|
||||
class MockSessionService
|
||||
: public GridMate::SessionService
|
||||
{
|
||||
public:
|
||||
MockSessionService()
|
||||
: SessionService(GridMate::SessionServiceDesc())
|
||||
{
|
||||
}
|
||||
|
||||
~MockSessionService()
|
||||
{
|
||||
m_activeSearches.clear();
|
||||
m_gridMate = nullptr;
|
||||
}
|
||||
|
||||
MOCK_CONST_METHOD0(IsReady, bool());
|
||||
};
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "GridMocks.h"
|
||||
|
||||
#include <GridMate/Replica/Interest/BitmaskInterestHandler.h>
|
||||
#include <GridMate/Replica/Interest/InterestManager.h>
|
||||
#include <GridMate/Replica/Interest/ProximityInterestHandler.h>
|
||||
|
||||
#include <AzFramework/Network/InterestManagerComponent.h>
|
||||
#include <AzCore/Socket/AzSocket.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
using testing::_;
|
||||
|
||||
class MockInterestManagerEvents
|
||||
: public AzFramework::InterestManagerEventsBus::Handler
|
||||
{
|
||||
public:
|
||||
MockInterestManagerEvents()
|
||||
{
|
||||
BusConnect();
|
||||
}
|
||||
|
||||
virtual ~MockInterestManagerEvents()
|
||||
{
|
||||
BusDisconnect();
|
||||
}
|
||||
|
||||
MOCK_METHOD1(OnInterestManagerActivate, void(GridMate::InterestManager* im));
|
||||
MOCK_METHOD1(OnInterestManagerDeactivate, void(GridMate::InterestManager* im));
|
||||
};
|
||||
|
||||
class InterestManagerComponentFixture
|
||||
: public AllocatorsFixture
|
||||
{
|
||||
public:
|
||||
InterestManagerComponentFixture()
|
||||
: AllocatorsFixture()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~InterestManagerComponentFixture()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
AZ::AzSock::Startup();
|
||||
|
||||
AllocatorsFixture::SetUp();
|
||||
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Create();
|
||||
m_gridMate = GridMate::GridMateCreate(GridMate::GridMateDesc());
|
||||
m_carrier = GridMate::DefaultCarrier::Create(GridMate::CarrierDesc(), m_gridMate);
|
||||
|
||||
m_sessionService = AZStd::make_unique<UnitTest::MockSessionService>();
|
||||
m_gridSession = AZStd::make_unique<UnitTest::MockSession>(m_sessionService.get());
|
||||
|
||||
m_replicaManagerDesc.m_carrier = m_carrier;
|
||||
m_replicaManagerDesc.m_myPeerId = AZ::Crc32(testing::UnitTest::GetInstance()->current_test_info()->test_case_name());
|
||||
m_replicaManagerDesc.m_roles = GridMate::ReplicaMgrDesc::Role_SyncHost;
|
||||
m_replicaManager = AZStd::make_unique<GridMate::ReplicaManager>();
|
||||
m_replicaManager->Init(m_replicaManagerDesc);
|
||||
|
||||
m_gridSession->SetReplicaManager(m_replicaManager.get());
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_gridSession = nullptr;
|
||||
m_sessionService = nullptr;
|
||||
|
||||
m_replicaManager->Shutdown();
|
||||
m_replicaManager = nullptr;
|
||||
|
||||
m_carrier->Shutdown();
|
||||
delete m_carrier;
|
||||
GridMate::GridMateDestroy(m_gridMate);
|
||||
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Destroy();
|
||||
AllocatorsFixture::TearDown();
|
||||
|
||||
AZ::AzSock::Cleanup();
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<UnitTest::MockSessionService> m_sessionService;
|
||||
AZStd::unique_ptr<UnitTest::MockSession> m_gridSession;
|
||||
|
||||
GridMate::IGridMate* m_gridMate;
|
||||
GridMate::Carrier* m_carrier;
|
||||
|
||||
GridMate::ReplicaMgrDesc m_replicaManagerDesc;
|
||||
AZStd::unique_ptr<GridMate::ReplicaManager> m_replicaManager;
|
||||
};
|
||||
|
||||
TEST_F(InterestManagerComponentFixture, TestNetworkSessionDeactivate)
|
||||
{
|
||||
// Using StrictMock here will ensure that the test fails if any of the events fire (as no EXPECT_CALL has been set).
|
||||
testing::StrictMock<MockInterestManagerEvents> interestManagerEvents;
|
||||
AzFramework::InterestManagerComponent interestManagerComponent;
|
||||
|
||||
// This will connect the component to the NetBindingSystemEventsBus
|
||||
interestManagerComponent.Activate();
|
||||
|
||||
// Ensure that the interest manager component handles receiving OnNetworkSessionDeactivated for a session that was never activated.
|
||||
// This can happen in the event of a client failing to connect to a host.
|
||||
AzFramework::NetBindingSystemEventsBus::Broadcast(
|
||||
&AzFramework::NetBindingSystemEvents::OnNetworkSessionDeactivated, m_gridSession.get());
|
||||
|
||||
interestManagerComponent.Deactivate();
|
||||
}
|
||||
|
||||
TEST_F(InterestManagerComponentFixture, TestNetworkSessionActivateAndDeactivate)
|
||||
{
|
||||
// Using StrictMock here will ensure that the test fails if any of the events fire (as no EXPECT_CALL has been set).
|
||||
testing::StrictMock<MockInterestManagerEvents> interestManagerEvents;
|
||||
AzFramework::InterestManagerComponent interestManagerComponent;
|
||||
GridMate::ReplicaChunkDescriptorTable::Get().RegisterChunkType<GridMate::BitmaskInterestChunk>();
|
||||
GridMate::ReplicaChunkDescriptorTable::Get().RegisterChunkType<GridMate::ProximityInterestChunk>();
|
||||
|
||||
// This will connect the component to the NetBindingSystemEventsBus
|
||||
interestManagerComponent.Activate();
|
||||
|
||||
// Golden path test that the interest manager component behaves as expected under normal conditions
|
||||
// (receiving OnNetworkSessionActivated followed by OnNetworkSessionDeactivated).
|
||||
testing::Expectation activationEvent = EXPECT_CALL(interestManagerEvents, OnInterestManagerActivate(_))
|
||||
.Times(1);
|
||||
AzFramework::NetBindingSystemEventsBus::Broadcast(
|
||||
&AzFramework::NetBindingSystemEvents::OnNetworkSessionActivated, m_gridSession.get());
|
||||
|
||||
EXPECT_CALL(interestManagerEvents, OnInterestManagerDeactivate(_))
|
||||
.Times(1)
|
||||
.After(activationEvent);
|
||||
AzFramework::NetBindingSystemEventsBus::Broadcast(
|
||||
&AzFramework::NetBindingSystemEvents::OnNetworkSessionDeactivated, m_gridSession.get());
|
||||
|
||||
interestManagerComponent.Deactivate();
|
||||
}
|
||||
}
|
||||
@@ -1,600 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/std/parallel/thread.h>
|
||||
#include <AzCore/std/containers/ring_buffer.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzFramework/Network/NetBindingComponent.h>
|
||||
#include <AzFramework/Network/NetBindingSystemComponent.h>
|
||||
#include <AzFramework/Network/NetBindable.h>
|
||||
#include <GridMate/GridMate.h>
|
||||
#include <GridMate/Session/LANSession.h>
|
||||
#include <GridMate/Replica/ReplicaChunkDescriptor.h>
|
||||
#include <GridMate/Replica/ReplicaChunk.h>
|
||||
#include <GridMate/Replica/ReplicaFunctions.h>
|
||||
#include <GridMate/Replica/DataSet.h>
|
||||
#include <GridMate/Replica/RemoteProcedureCall.h>
|
||||
#include <GridMate/Serialize/DataMarshal.h>
|
||||
#include <GridMate/Serialize/CompressionMarshal.h>
|
||||
#include <GridMate/Carrier/Utils.h>
|
||||
|
||||
#include <AzCore/Asset/AssetManagerComponent.h>
|
||||
#include <AzCore/Memory/MemoryComponent.h>
|
||||
#include <AzCore/Memory/AllocationRecords.h>
|
||||
#include <AzFramework/Entity/GameEntityContextComponent.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
#if 0
|
||||
using namespace AZ;
|
||||
|
||||
/**
|
||||
*/
|
||||
class NetBindingTestComponent
|
||||
: public AZ::Component
|
||||
, public AzFramework::NetBindable
|
||||
{
|
||||
friend class NetBindingComponentChunk;
|
||||
|
||||
public:
|
||||
AZ_COMPONENT(NetBindingTestComponent, "{DE5CF1C0-B4B6-4BB0-86FE-936B400871E0}", AzFramework::NetBindable);
|
||||
|
||||
protected:
|
||||
class NetChunk
|
||||
: public GridMate::ReplicaChunk
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(NetChunk, AZ::SystemAllocator, 0);
|
||||
|
||||
static const char* GetChunkName() { return "NetBindingTestComponent::NetChunk"; }
|
||||
|
||||
bool IsReplicaMigratable() override { return false; }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// NetBindable
|
||||
GridMate::ReplicaChunkPtr GetNetworkBinding() override
|
||||
{
|
||||
AZ_TracePrintf("NetBinding", "NetBindingTestComponent::GetNetworkBinding()\n");
|
||||
m_chunk = GridMate::CreateReplicaChunk<NetChunk>();
|
||||
AZ_Assert(m_chunk, "Failed to create NetBindingTestComponent::NetChunk!");
|
||||
return m_chunk;
|
||||
}
|
||||
|
||||
void SetNetworkBinding(GridMate::ReplicaChunkPtr binding) override
|
||||
{
|
||||
AZ_TracePrintf("NetBinding", "NetBindingTestComponent::SetNetworkBinding()\n");
|
||||
AZ_TEST_ASSERT(binding);
|
||||
AZ_TEST_ASSERT(binding->GetDescriptor()->GetChunkTypeId() == GridMate::ReplicaChunkClassId(NetChunk::GetChunkName()));
|
||||
m_chunk = AZStd::static_pointer_cast<NetChunk>(binding);
|
||||
}
|
||||
|
||||
void UnbindFromNetwork() override
|
||||
{
|
||||
if (m_chunk)
|
||||
{
|
||||
AZ_TracePrintf("NetBinding", "NetBindingTestComponent::UnbindFromNetwork()\n");
|
||||
m_chunk = nullptr;
|
||||
}
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component
|
||||
static void Reflect(AZ::ReflectContext* reflection)
|
||||
{
|
||||
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection);
|
||||
if (serializeContext)
|
||||
{
|
||||
serializeContext->Class<NetBindingTestComponent, AZ::Component, AzFramework::NetBindable>()
|
||||
;
|
||||
}
|
||||
|
||||
// We also need to register the chunk type, and this would be a good time to do so.
|
||||
GridMate::ReplicaChunkDescriptorTable::Get().RegisterChunkType<NetChunk>();
|
||||
}
|
||||
|
||||
void Activate() override
|
||||
{
|
||||
AZ_TracePrintf("NetBinding", "NetBindingTestComponent::Activate()\n");
|
||||
}
|
||||
|
||||
void Deactivate() override
|
||||
{
|
||||
AZ_TracePrintf("NetBinding", "NetBindingTestComponent::Deactivate()\n");
|
||||
UnbindFromNetwork();
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
AZStd::intrusive_ptr<NetChunk> m_chunk;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fakes the behavior of NetBindingSystemContextData on the host side
|
||||
*/
|
||||
class FakeNetBindingContextChunk
|
||||
: public GridMate::ReplicaChunk
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(FakeNetBindingContextChunk, AZ::SystemAllocator, 0);
|
||||
|
||||
static const char* GetChunkName() { return "NetBindingSystemContextData"; } // We are pretending to be a NetBindingSystemContextData
|
||||
|
||||
FakeNetBindingContextChunk()
|
||||
: m_bindingContextSequence("BindingContextSequence", AzFramework::UnspecifiedNetBindingContextSequence)
|
||||
{
|
||||
}
|
||||
|
||||
bool IsReplicaMigratable() override { return true; }
|
||||
|
||||
GridMate::DataSet<AZ::u32, GridMate::VlqU32Marshaler> m_bindingContextSequence;
|
||||
};
|
||||
|
||||
/*
|
||||
* NetBindingSystemComponentLifecycleTest
|
||||
*/
|
||||
class NetBindingSystemComponentLifecycleTest
|
||||
: public GridMate::SessionEventBus::Handler
|
||||
, public AzFramework::NetBindingHandlerBus::Handler
|
||||
{
|
||||
public:
|
||||
void OnSessionCreated(GridMate::GridSession* session) override
|
||||
{
|
||||
if (session == m_session)
|
||||
{
|
||||
if (session->IsHost())
|
||||
{
|
||||
EBUS_EVENT(AzFramework::NetBindingSystemBus, OnNetworkSessionActivated, session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnSessionJoined(GridMate::GridSession* session) override
|
||||
{
|
||||
if (session == m_session)
|
||||
{
|
||||
EBUS_EVENT(AzFramework::NetBindingSystemBus, OnNetworkSessionActivated, session);
|
||||
}
|
||||
}
|
||||
|
||||
void OnSessionDelete(GridMate::GridSession* session)
|
||||
{
|
||||
if (session == m_session)
|
||||
{
|
||||
EBUS_EVENT(AzFramework::NetBindingSystemBus, OnNetworkSessionDeactivated, session);
|
||||
m_session = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void BindToNetwork(GridMate::ReplicaPtr bindTo) override
|
||||
{
|
||||
// Verify that BindToNetwork() is not called more than once
|
||||
AZ_TEST_ASSERT(!m_receivedBindEvent);
|
||||
m_receivedBindEvent = true;
|
||||
|
||||
// Test that now we should be binding to the network
|
||||
bool shouldBindToNetwork = false;
|
||||
EBUS_EVENT_RESULT(shouldBindToNetwork, AzFramework::NetBindingSystemBus, ShouldBindToNetwork);
|
||||
AZ_TEST_ASSERT(shouldBindToNetwork);
|
||||
|
||||
// Verify that the context sequence is no longer unspecified
|
||||
AzFramework::NetBindingContextSequence contextSequence = AzFramework::UnspecifiedNetBindingContextSequence;
|
||||
EBUS_EVENT_RESULT(contextSequence, AzFramework::NetBindingSystemBus, GetCurrentContextSequence);
|
||||
AZ_TEST_ASSERT(contextSequence != AzFramework::UnspecifiedNetBindingContextSequence);
|
||||
}
|
||||
|
||||
void UnbindFromNetwork() override
|
||||
{
|
||||
// Verify that UnbindFromNetwork() is not called more than once
|
||||
AZ_TEST_ASSERT(!m_receivedUnbindEvent);
|
||||
m_receivedUnbindEvent = true;
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
// Setup
|
||||
AZ::ComponentApplication app;
|
||||
AZ::ComponentApplication::Descriptor appDesc;
|
||||
appDesc.m_recordsMode = AZ::Debug::AllocationRecords::RECORD_FULL;
|
||||
AZ::Entity* systemEntity = app.Create(appDesc);
|
||||
|
||||
app.RegisterComponentDescriptor(AzFramework::NetBindingSystemComponent::CreateDescriptor());
|
||||
app.RegisterComponentDescriptor(AzFramework::GameEntityContextComponent::CreateDescriptor());
|
||||
|
||||
systemEntity->Init();
|
||||
systemEntity->CreateComponent<AZ::MemoryComponent>();
|
||||
systemEntity->CreateComponent<AZ::AssetManagerComponent>();
|
||||
systemEntity->CreateComponent<AzFramework::GameEntityContextComponent>();
|
||||
systemEntity->CreateComponent<AzFramework::NetBindingSystemComponent>();
|
||||
systemEntity->Activate();
|
||||
AzFramework::NetBindingHandlerBus::Handler::BusConnect();
|
||||
|
||||
GridMate::GridMateDesc gridMateDesc;
|
||||
GridMate::IGridMate* gridMate = GridMate::GridMateCreate(gridMateDesc);
|
||||
GridMate::GridMateAllocatorMP::Descriptor allocDesc;
|
||||
allocDesc.m_stackRecordLevels = 15;
|
||||
allocDesc.m_custom = &AZ::AllocatorInstance<AZ::SystemAllocator>::Get();
|
||||
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Create(allocDesc);
|
||||
if (AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Get().GetRecords())
|
||||
{
|
||||
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Get().GetRecords()->SetMode(AZ::Debug::AllocationRecords::RECORD_FULL);
|
||||
}
|
||||
GridMate::StartGridMateService<GridMate::LANSessionService>(gridMate, GridMate::SessionServiceDesc());
|
||||
GridMate::SessionEventBus::Handler::BusConnect(gridMate);
|
||||
|
||||
// Test offline behavior
|
||||
{
|
||||
bool shouldBindToNetwork = true;
|
||||
EBUS_EVENT_RESULT(shouldBindToNetwork, AzFramework::NetBindingSystemBus, ShouldBindToNetwork);
|
||||
AZ_TEST_ASSERT(!shouldBindToNetwork);
|
||||
|
||||
AzFramework::NetBindingContextSequence offlineContextSequence = 0xBADF00D;
|
||||
EBUS_EVENT_RESULT(offlineContextSequence, AzFramework::NetBindingSystemBus, GetCurrentContextSequence);
|
||||
AZ_TEST_ASSERT(offlineContextSequence == AzFramework::UnspecifiedNetBindingContextSequence);
|
||||
}
|
||||
|
||||
// Test host-side behavior
|
||||
{
|
||||
m_receivedBindEvent = m_receivedUnbindEvent = false;
|
||||
|
||||
// Host a session
|
||||
GridMate::CarrierDesc carrierDesc;
|
||||
carrierDesc.m_enableDisconnectDetection = true;
|
||||
GridMate::LANSessionParams sessionParams;
|
||||
sessionParams.m_numPublicSlots = 10;
|
||||
sessionParams.m_flags = 0;
|
||||
sessionParams.m_port = HOST_PORT;
|
||||
sessionParams.m_params[sessionParams.m_numParams].m_id = "filter";
|
||||
sessionParams.m_params[sessionParams.m_numParams].m_value = GridMate::Utils::GetMachineAddress();
|
||||
sessionParams.m_numParams++;
|
||||
m_session = gridMate->GetMultiplayerService()->HostSession(&sessionParams, carrierDesc);
|
||||
|
||||
int nFrame = 0;
|
||||
while (m_session)
|
||||
{
|
||||
if (nFrame == 10)
|
||||
{
|
||||
// Verify that BindToNetwork() has been called
|
||||
AZ_TEST_ASSERT(m_receivedBindEvent);
|
||||
|
||||
// Verify that we have a valid context sequence
|
||||
AzFramework::NetBindingContextSequence contextSequence1 = AzFramework::UnspecifiedNetBindingContextSequence;
|
||||
EBUS_EVENT_RESULT(contextSequence1, AzFramework::NetBindingSystemBus, GetCurrentContextSequence);
|
||||
AZ_TEST_ASSERT(contextSequence1 != AzFramework::UnspecifiedNetBindingContextSequence);
|
||||
|
||||
EBUS_EVENT(AzFramework::GameEntityContextRequestBus, ResetGameContext);
|
||||
|
||||
// Verify that the context sequence was incremented
|
||||
AzFramework::NetBindingContextSequence contextSequence2 = contextSequence1;
|
||||
EBUS_EVENT_RESULT(contextSequence2, AzFramework::NetBindingSystemBus, GetCurrentContextSequence);
|
||||
AZ_TEST_ASSERT(contextSequence2 != AzFramework::UnspecifiedNetBindingContextSequence);
|
||||
AZ_TEST_ASSERT(contextSequence2 > contextSequence1);
|
||||
|
||||
m_session->Leave(false);
|
||||
}
|
||||
|
||||
app.Tick();
|
||||
gridMate->Update();
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(10));
|
||||
nFrame++;
|
||||
}
|
||||
|
||||
// Verify that we should no longer bind to the network
|
||||
bool shouldBindToNetwork = true;
|
||||
EBUS_EVENT_RESULT(shouldBindToNetwork, AzFramework::NetBindingSystemBus, ShouldBindToNetwork);
|
||||
AZ_TEST_ASSERT(!shouldBindToNetwork);
|
||||
|
||||
// Verify that the context sequence was reset to unspecified
|
||||
AzFramework::NetBindingContextSequence offlineContextSequence = 0xBADF00D;
|
||||
EBUS_EVENT_RESULT(offlineContextSequence, AzFramework::NetBindingSystemBus, GetCurrentContextSequence);
|
||||
AZ_TEST_ASSERT(offlineContextSequence == AzFramework::UnspecifiedNetBindingContextSequence);
|
||||
}
|
||||
|
||||
// Test nonhost-side behavior by faking the behavior on the host side and then joining the host session.
|
||||
{
|
||||
m_receivedBindEvent = m_receivedUnbindEvent = false;
|
||||
|
||||
// Host a session
|
||||
GridMate::CarrierDesc carrierDesc;
|
||||
carrierDesc.m_enableDisconnectDetection = true;
|
||||
GridMate::LANSessionParams sessionParams;
|
||||
sessionParams.m_numPublicSlots = 10;
|
||||
sessionParams.m_flags = 0;
|
||||
sessionParams.m_port = HOST_PORT;
|
||||
sessionParams.m_params[sessionParams.m_numParams].m_id = "filter";
|
||||
sessionParams.m_params[sessionParams.m_numParams].m_value = GridMate::Utils::GetMachineAddress();
|
||||
sessionParams.m_numParams++;
|
||||
GridMate::GridSession* hostSession = gridMate->GetMultiplayerService()->HostSession(&sessionParams, carrierDesc);
|
||||
|
||||
// Add the fake context replica on the host and set the context sequence to 1
|
||||
GridMate::ReplicaPtr replica = GridMate::Replica::CreateReplica("Potato");
|
||||
FakeNetBindingContextChunk* contextChunk = GridMate::CreateReplicaChunk<FakeNetBindingContextChunk>();
|
||||
replica->AttachReplicaChunk(contextChunk);
|
||||
while (!hostSession->IsReady())
|
||||
{
|
||||
gridMate->Update();
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(10));
|
||||
}
|
||||
hostSession->GetReplicaMgr()->AddMaster(replica);
|
||||
contextChunk->m_bindingContextSequence.Set(1);
|
||||
|
||||
int nFrame = 0;
|
||||
while (m_session)
|
||||
{
|
||||
if (nFrame == 10)
|
||||
{
|
||||
// Join the hosted session
|
||||
GridMate::SessionIdInfo sessionInfo;
|
||||
sessionInfo.m_sessionId = hostSession->GetId();
|
||||
m_session = gridMate->GetMultiplayerService()->JoinSession(&sessionInfo, GridMate::JoinParams(), carrierDesc);
|
||||
}
|
||||
|
||||
if (nFrame == 20)
|
||||
{
|
||||
// Verify that BindToNetwork() has been called
|
||||
AZ_TEST_ASSERT(m_receivedBindEvent);
|
||||
|
||||
// Verify that we have a valid context sequence
|
||||
AzFramework::NetBindingContextSequence contextSequence = AzFramework::UnspecifiedNetBindingContextSequence;
|
||||
EBUS_EVENT_RESULT(contextSequence, AzFramework::NetBindingSystemBus, GetCurrentContextSequence);
|
||||
AZ_TEST_ASSERT(contextSequence == contextChunk->m_bindingContextSequence.Get());
|
||||
|
||||
// Simulate a context switch on the host
|
||||
contextChunk->m_bindingContextSequence.Set(contextChunk->m_bindingContextSequence.Get() + 1);
|
||||
}
|
||||
|
||||
if (nFrame == 30)
|
||||
{
|
||||
// Verify that the context sequence was incremented
|
||||
AzFramework::NetBindingContextSequence contextSequence = AzFramework::UnspecifiedNetBindingContextSequence;
|
||||
EBUS_EVENT_RESULT(contextSequence, AzFramework::NetBindingSystemBus, GetCurrentContextSequence);
|
||||
AZ_TEST_ASSERT(contextSequence == contextChunk->m_bindingContextSequence.Get());
|
||||
|
||||
hostSession->Leave(false);
|
||||
}
|
||||
|
||||
app.Tick();
|
||||
gridMate->Update();
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(10));
|
||||
nFrame++;
|
||||
}
|
||||
|
||||
// Verify that we should no longer bind to the network
|
||||
bool shouldBindToNetwork = true;
|
||||
EBUS_EVENT_RESULT(shouldBindToNetwork, AzFramework::NetBindingSystemBus, ShouldBindToNetwork);
|
||||
AZ_TEST_ASSERT(!shouldBindToNetwork);
|
||||
|
||||
// Verify that the context sequence was reset to unspecified
|
||||
AzFramework::NetBindingContextSequence offlineContextSequence = 0xBADF00D;
|
||||
EBUS_EVENT_RESULT(offlineContextSequence, AzFramework::NetBindingSystemBus, GetCurrentContextSequence);
|
||||
AZ_TEST_ASSERT(offlineContextSequence == AzFramework::UnspecifiedNetBindingContextSequence);
|
||||
}
|
||||
|
||||
// Clean up
|
||||
GridMate::SessionEventBus::Handler::BusDisconnect();
|
||||
GridMate::GridMateDestroy(gridMate);
|
||||
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Destroy();
|
||||
AzFramework::NetBindingHandlerBus::Handler::BusDisconnect();
|
||||
app.Destroy();
|
||||
}
|
||||
|
||||
static const int HOST_PORT = 5000;
|
||||
|
||||
GridMate::GridSession* m_session;
|
||||
bool m_receivedBindEvent;
|
||||
bool m_receivedUnbindEvent;
|
||||
};
|
||||
|
||||
/*
|
||||
* NetBindingFeatureTest (requires two instances)
|
||||
*/
|
||||
class NetBindingFeatureTest
|
||||
: public GridMate::SessionEventBus::Handler
|
||||
{
|
||||
public:
|
||||
void OnSessionCreated(GridMate::GridSession* session) override
|
||||
{
|
||||
if (session == m_session)
|
||||
{
|
||||
if (session->IsHost())
|
||||
{
|
||||
EBUS_EVENT(AzFramework::NetBindingSystemBus, OnNetworkSessionActivated, session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnSessionJoined(GridMate::GridSession* session) override
|
||||
{
|
||||
if (session == m_session)
|
||||
{
|
||||
EBUS_EVENT(AzFramework::NetBindingSystemBus, OnNetworkSessionActivated, session);
|
||||
}
|
||||
}
|
||||
|
||||
void OnSessionDelete(GridMate::GridSession* session)
|
||||
{
|
||||
if (session == m_session)
|
||||
{
|
||||
EBUS_EVENT(AzFramework::NetBindingSystemBus, OnNetworkSessionDeactivated, session);
|
||||
m_session = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void OnGridSearchComplete(GridMate::GridSearch* results) override
|
||||
{
|
||||
if (results == m_search)
|
||||
{
|
||||
GridMate::CarrierDesc carrierDesc;
|
||||
carrierDesc.m_enableDisconnectDetection = true;
|
||||
|
||||
// Create an entity before we get in the session
|
||||
AZ_TracePrintf("NetBinding", "Spawning master entity...\n");
|
||||
AZ::Entity* newEntity = nullptr;
|
||||
newEntity = aznew Entity;
|
||||
newEntity->CreateComponent<NetBindingTestComponent>();
|
||||
newEntity->CreateComponent<AzFramework::NetBindingComponent>();
|
||||
newEntity->Init();
|
||||
newEntity->Activate();
|
||||
m_entities.push_back(newEntity);
|
||||
|
||||
if (results->GetNumResults() == 0)
|
||||
{
|
||||
// Host a session instead
|
||||
GridMate::LANSessionParams sessionParams;
|
||||
sessionParams.m_numPublicSlots = 10;
|
||||
sessionParams.m_flags = 0;
|
||||
sessionParams.m_port = HOST_PORT;
|
||||
sessionParams.m_params[sessionParams.m_numParams].m_id = "filter";
|
||||
sessionParams.m_params[sessionParams.m_numParams].m_value = GridMate::Utils::GetMachineAddress();
|
||||
sessionParams.m_numParams++;
|
||||
m_session = m_gridMate->GetMultiplayerService()->HostSession(&sessionParams, carrierDesc);
|
||||
|
||||
m_search->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Join the session
|
||||
GridMate::JoinParams joinParams;
|
||||
m_session = m_gridMate->GetMultiplayerService()->JoinSession(results->GetResult(0), joinParams, carrierDesc);
|
||||
}
|
||||
m_search = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void OnMemberJoined(GridMate::GridSession* session, GridMate::GridMember* member) override
|
||||
{
|
||||
if (session == m_session)
|
||||
{
|
||||
if (session->IsHost())
|
||||
{
|
||||
if (member != session->GetMyMember())
|
||||
{
|
||||
// Spawn an entity after session creation
|
||||
AZ_TracePrintf("NetBinding", "Spawning master entity...\n");
|
||||
AZ::Entity* newEntity = nullptr;
|
||||
EBUS_EVENT_RESULT(newEntity, AzFramework::GameEntityContextRequestBus, CreateGameEntity, "ReplicatedEntity2");
|
||||
newEntity->CreateComponent<NetBindingTestComponent>();
|
||||
newEntity->CreateComponent<AzFramework::NetBindingComponent>();
|
||||
newEntity->Init();
|
||||
newEntity->Activate();
|
||||
m_entities.push_back(newEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
m_gridMate = nullptr;
|
||||
m_session = nullptr;
|
||||
|
||||
AZ::ComponentApplication app;
|
||||
AZ::ComponentApplication::Descriptor appDesc;
|
||||
AZ::Entity* systemEntity = app.Create(appDesc);
|
||||
|
||||
app.RegisterComponentDescriptor(AzFramework::NetBindingSystemComponent::CreateDescriptor());
|
||||
app.RegisterComponentDescriptor(AzFramework::NetBindingComponent::CreateDescriptor());
|
||||
app.RegisterComponentDescriptor(NetBindingTestComponent::CreateDescriptor());
|
||||
app.RegisterComponentDescriptor(AzFramework::GameEntityContextComponent::CreateDescriptor());
|
||||
|
||||
systemEntity->Init();
|
||||
systemEntity->CreateComponent<AZ::MemoryComponent>();
|
||||
systemEntity->CreateComponent<AZ::AssetManagerComponent>();
|
||||
systemEntity->CreateComponent<AzFramework::GameEntityContextComponent>();
|
||||
systemEntity->CreateComponent<AzFramework::NetBindingSystemComponent>();
|
||||
systemEntity->Activate();
|
||||
|
||||
GridMate::GridMateDesc gridMateDesc;
|
||||
m_gridMate = GridMate::GridMateCreate(gridMateDesc);
|
||||
|
||||
GridMate::GridMateAllocatorMP::Descriptor allocDesc;
|
||||
allocDesc.m_custom = &AZ::AllocatorInstance<AZ::SystemAllocator>::Get();
|
||||
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Create(allocDesc);
|
||||
|
||||
GridMate::StartGridMateService<GridMate::LANSessionService>(m_gridMate, GridMate::SessionServiceDesc());
|
||||
|
||||
GridMate::SessionEventBus::Handler::BusConnect(m_gridMate);
|
||||
|
||||
// Search for an existing session
|
||||
// If a session is not found, we will host a session from within the search callback.
|
||||
{
|
||||
GridMate::LANSearchParams searchParams;
|
||||
searchParams.m_serverPort = HOST_PORT;
|
||||
searchParams.m_params[searchParams.m_numParams].m_id = "filter";
|
||||
searchParams.m_params[searchParams.m_numParams].m_value = GridMate::Utils::GetMachineAddress();
|
||||
searchParams.m_params[searchParams.m_numParams].m_op = GridMate::GridSessionSearchOperators::SSO_OPERATOR_EQUAL;
|
||||
searchParams.m_numParams++;
|
||||
m_search = m_gridMate->GetMultiplayerService()->StartGridSearch(&searchParams);
|
||||
|
||||
while (m_search)
|
||||
{
|
||||
m_gridMate->Update();
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(10));
|
||||
}
|
||||
}
|
||||
|
||||
// Tick for a while
|
||||
//static int nTicks = 100;
|
||||
for (int i = 0; m_session; ++i)
|
||||
{
|
||||
if (m_session->IsHost())
|
||||
{
|
||||
if (i > 4000 && m_session->GetNumberOfMembers() == 1)
|
||||
{
|
||||
m_session->Leave(false);
|
||||
}
|
||||
}
|
||||
|
||||
m_gridMate->Update();
|
||||
app.Tick();
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
GridMate::SessionEventBus::Handler::BusDisconnect();
|
||||
|
||||
GridMate::GridMateDestroy(m_gridMate);
|
||||
|
||||
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Destroy();
|
||||
|
||||
for (AZ::Entity* entity : m_entities)
|
||||
{
|
||||
AzFramework::EntityContextId contextId = AzFramework::EntityContextId::CreateNull();
|
||||
EBUS_EVENT_ID_RESULT(contextId, entity->GetId(), AzFramework::EntityIdContextQueryBus, GetOwningContextId);
|
||||
if (contextId.IsNull())
|
||||
{
|
||||
delete entity;
|
||||
}
|
||||
else
|
||||
{
|
||||
EBUS_EVENT(AzFramework::GameEntityContextRequestBus, DestroyGameEntity, entity);
|
||||
}
|
||||
}
|
||||
|
||||
app.Destroy();
|
||||
}
|
||||
|
||||
static const int HOST_PORT = 6000;
|
||||
|
||||
GridMate::IGridMate* m_gridMate;
|
||||
GridMate::GridSession* m_session;
|
||||
GridMate::GridSearch* m_search;
|
||||
AZStd::fixed_vector<AZ::Entity*, 10> m_entities;
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
AZ_TEST_SUITE(NetBinding)
|
||||
//AZ_TEST(UnitTest::NetBindingSystemComponentLifecycleTest)
|
||||
//AZ_TEST(UnitTest::NetBindingFeatureTest)
|
||||
AZ_TEST_SUITE_END
|
||||
@@ -1,330 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AZCORE_UNITTEST_NETBINDINGMOCKS_H
|
||||
#define AZCORE_UNITTEST_NETBINDINGMOCKS_H
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <AzFramework/Entity/GameEntityContextBus.h>
|
||||
#include <AzFramework/Entity/SliceGameEntityOwnershipServiceBus.h>
|
||||
#include <AzCore/Slice/SliceComponent.h>
|
||||
#include <AzFramework/Network/NetBindingHandlerBus.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class MockGameEntityContext
|
||||
: public AzFramework::GameEntityContextRequestBus::Handler
|
||||
, public AzFramework::SliceGameEntityOwnershipServiceRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
MockGameEntityContext()
|
||||
{
|
||||
AzFramework::GameEntityContextRequestBus::Handler::BusConnect();
|
||||
AzFramework::SliceGameEntityOwnershipServiceRequestBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
~MockGameEntityContext()
|
||||
{
|
||||
AzFramework::SliceGameEntityOwnershipServiceRequestBus::Handler::BusDisconnect();
|
||||
AzFramework::GameEntityContextRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
MOCK_METHOD3(InstantiateDynamicSlice, AzFramework::SliceInstantiationTicket(const AZ::Data::Asset<AZ::Data::AssetData>&, const AZ::Transform&, const AZ::IdUtils::Remapper<AZ::EntityId>::IdMapper&));
|
||||
MOCK_METHOD0(GetGameEntityContextId, AzFramework::EntityContextId());
|
||||
MOCK_METHOD1(CreateGameEntity, AZ::Entity*(const char*));
|
||||
MOCK_METHOD1(AddGameEntity, void (AZ::Entity*));
|
||||
MOCK_METHOD1(DestroyGameEntity, void (const AZ::EntityId&));
|
||||
MOCK_METHOD1(DestroyGameEntityAndDescendants, void (const AZ::EntityId&));
|
||||
MOCK_METHOD1(ActivateGameEntity, void (const AZ::EntityId&));
|
||||
MOCK_METHOD1(DeactivateGameEntity, void (const AZ::EntityId&));
|
||||
MOCK_METHOD1(DestroyDynamicSliceByEntity, bool (const AZ::EntityId&));
|
||||
MOCK_METHOD2(LoadFromStream, bool (AZ::IO::GenericStream&, bool));
|
||||
MOCK_METHOD0(ResetGameContext, void ());
|
||||
MOCK_METHOD1(GetEntityName, AZStd::string (const AZ::EntityId&));
|
||||
MOCK_METHOD1(DestroySliceByEntity, bool(const AZ::EntityId&));
|
||||
MOCK_METHOD1(CreateGameEntityForBehaviorContext, AzFramework::BehaviorEntity (const char *));
|
||||
MOCK_METHOD1(CancelDynamicSliceInstantiation, void (const AzFramework::SliceInstantiationTicket &));
|
||||
};
|
||||
|
||||
class MockNetBindingSystemContextData
|
||||
: public AzFramework::NetBindingSystemContextData
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(MockNetBindingSystemContextData, AZ::SystemAllocator, 0);
|
||||
|
||||
static const char* GetChunkName()
|
||||
{
|
||||
return "MockNetBindingSystemContextData";
|
||||
}
|
||||
|
||||
MOCK_METHOD1(OnAttachedToReplica, void (GridMate::Replica*));
|
||||
MOCK_METHOD1(OnDetachedFromReplica, void (GridMate::Replica*));
|
||||
MOCK_METHOD1(UpdateChunk, void (const GridMate::ReplicaContext&));
|
||||
MOCK_METHOD1(UpdateFromChunk, void (const GridMate::ReplicaContext&));
|
||||
MOCK_METHOD2(AcceptChangeOwnership, bool (GridMate::PeerId, const GridMate::ReplicaContext&));
|
||||
MOCK_METHOD1(OnReplicaChangeOwnership, void (const GridMate::ReplicaContext&));
|
||||
MOCK_METHOD0(IsUpdateFromReplicaEnabled, bool ());
|
||||
MOCK_CONST_METHOD1(ShouldSendToPeer, bool (GridMate::ReplicaPeer*));
|
||||
MOCK_METHOD1(CalculateDirtyDataSetMask, AZ::u32 (GridMate::MarshalContext&));
|
||||
MOCK_METHOD1(OnDataSetChanged, void (const GridMate::DataSetBase&));
|
||||
MOCK_METHOD2(Marshal, void (GridMate::MarshalContext&, AZ::u32));
|
||||
MOCK_METHOD2(Unmarshal, void (GridMate::UnmarshalContext&, AZ::u32));
|
||||
MOCK_METHOD0(IsReplicaMigratable, bool ());
|
||||
MOCK_METHOD0(IsBroadcast, bool ());
|
||||
MOCK_METHOD1(OnReplicaActivate, void (const GridMate::ReplicaContext&));
|
||||
MOCK_METHOD1(OnReplicaDeactivate, void (const GridMate::ReplicaContext&));
|
||||
|
||||
/**
|
||||
* \brief Helper method for GoogleMock to call NetBindingSystemContextData::OnReplicaActivate
|
||||
*/
|
||||
void Base_OnReplicaActivate(const GridMate::ReplicaContext& rc)
|
||||
{
|
||||
NetBindingSystemContextData::OnReplicaActivate(rc);
|
||||
}
|
||||
|
||||
MOCK_METHOD0(GetReplicaManager, GridMate::ReplicaManager* ());
|
||||
MOCK_METHOD0(ShouldBindToNetwork, bool ());
|
||||
};
|
||||
|
||||
class MockReplicaManager
|
||||
: public GridMate::ReplicaManager
|
||||
{
|
||||
public:
|
||||
MOCK_METHOD2(OnIncomingConnection, void (GridMate::Carrier*, GridMate::ConnectionID));
|
||||
MOCK_METHOD3(OnFailedToConnect, void (GridMate::Carrier*, GridMate::ConnectionID, GridMate::CarrierDisconnectReason));
|
||||
MOCK_METHOD3(OnDriverError, void (GridMate::Carrier*, GridMate::ConnectionID, const GridMate::DriverError&));
|
||||
MOCK_METHOD3(OnSecurityError, void (GridMate::Carrier*, GridMate::ConnectionID, const GridMate::SecurityError&));
|
||||
MOCK_METHOD1(Destroy, bool (GridMate::Replica*));
|
||||
MOCK_METHOD2(GetReplicaContext, void (const GridMate::Replica*, GridMate::ReplicaContext&));
|
||||
MOCK_METHOD2(OnConnectionEstablished, void (GridMate::Carrier*, GridMate::ConnectionID));
|
||||
MOCK_METHOD3(OnDisconnect, void (GridMate::Carrier*, GridMate::ConnectionID, GridMate::CarrierDisconnectReason));
|
||||
MOCK_METHOD3(OnRateChange, void (GridMate::Carrier*, GridMate::ConnectionID, AZ::u32));
|
||||
MOCK_METHOD1(FindReplica, GridMate::ReplicaPtr (GridMate::ReplicaId));
|
||||
};
|
||||
|
||||
class MockAssetHandler
|
||||
: public AZ::Data::AssetHandler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(MockAssetHandler, AZ::SystemAllocator, 0)
|
||||
|
||||
MOCK_METHOD2(CreateAsset, AZ::Data::AssetPtr (const AZ::Data::AssetId&, const AZ::Data::AssetType&));
|
||||
MOCK_METHOD3(LoadAssetData, AZ::Data::AssetHandler::LoadResult (
|
||||
const AZ::Data::Asset<AZ::Data::AssetData>&,
|
||||
AZStd::shared_ptr<AZ::Data::AssetDataStream>,
|
||||
const AZ::Data::AssetFilterCB&));
|
||||
MOCK_METHOD2(SaveAssetData, bool (const AZ::Data::Asset<AZ::Data::AssetData>&, AZ::IO::GenericStream*));
|
||||
MOCK_METHOD3(InitAsset, void (const AZ::Data::Asset<AZ::Data::AssetData>&, bool, bool));
|
||||
MOCK_METHOD1(DestroyAsset, void (AZ::Data::AssetPtr));
|
||||
MOCK_METHOD1(GetHandledAssetTypes, void (AZStd::vector<AZ::Data::AssetType>&));
|
||||
MOCK_CONST_METHOD1(CanHandleAsset, bool (const AZ::Data::AssetId&));
|
||||
};
|
||||
|
||||
class MockAsset
|
||||
: public AZ::DynamicSliceAsset
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(MockAsset, "{78ABC204-452E-4621-A552-F04D3ABF1690}", DynamicSliceAsset);
|
||||
|
||||
MockAsset(const AZ::Data::AssetId& assetId = AZ::Data::AssetId())
|
||||
: DynamicSliceAsset(assetId)
|
||||
{
|
||||
}
|
||||
|
||||
~MockAsset() = default;
|
||||
};
|
||||
|
||||
class MockSliceReference
|
||||
: public AZ::SliceComponent::SliceReference
|
||||
{
|
||||
public:
|
||||
using SliceReference::SliceReference;
|
||||
|
||||
MOCK_METHOD1(CreateInstance, AZ::SliceComponent::SliceInstance*(const AZ::IdUtils::Remapper<AZ::EntityId>::IdMapper&));
|
||||
MOCK_METHOD2(CloneInstance, AZ::SliceComponent::SliceInstance*(AZ::SliceComponent::SliceInstance*, AZ::SliceComponent::EntityIdToEntityIdMap&));
|
||||
MOCK_METHOD1(FindInstance, AZ::SliceComponent::SliceInstance*(const AZ::SliceComponent::SliceInstanceId&));
|
||||
MOCK_METHOD1(RemoveInstance, bool(AZ::SliceComponent::SliceInstance*));
|
||||
MOCK_METHOD3(RemoveEntity, bool(AZ::EntityId, bool, AZ::SliceComponent::SliceInstance*));
|
||||
MOCK_CONST_METHOD0(GetInstances, const AZ::SliceComponent::SliceReference::SliceInstances&());
|
||||
MOCK_CONST_METHOD0(GetSliceAsset, const AZ::Data::Asset<AZ::SliceAsset>& ());
|
||||
MOCK_CONST_METHOD0(GetSliceComponent, AZ::SliceComponent*());
|
||||
MOCK_CONST_METHOD0(IsInstantiated, bool ());
|
||||
MOCK_CONST_METHOD3(GetInstanceEntityAncestry, bool(const AZ::EntityId&, AZ::SliceComponent::EntityAncestorList&, AZ::u32));
|
||||
MOCK_METHOD0(ComputeDataPatch, void());
|
||||
};
|
||||
|
||||
class MockSliceInstance
|
||||
: public AZ::SliceComponent::SliceInstance
|
||||
{
|
||||
public:
|
||||
using SliceInstance::SliceInstance;
|
||||
|
||||
void SetMockInstantiatedContainer(AZ::SliceComponent::InstantiatedContainer* newContainer)
|
||||
{
|
||||
m_instantiated = newContainer;
|
||||
|
||||
for (AZ::Entity* entity : m_instantiated->m_entities)
|
||||
{
|
||||
m_entityIdToBaseCache.insert(AZStd::make_pair(entity->GetId(), entity->GetId()));
|
||||
}
|
||||
|
||||
for (AZ::Entity* entity : m_instantiated->m_entities)
|
||||
{
|
||||
m_baseToNewEntityIdMap.insert(AZStd::make_pair(entity->GetId(), entity->GetId()));
|
||||
}
|
||||
}
|
||||
|
||||
MOCK_CONST_METHOD0(GetInstantiated, const AZ::SliceComponent::InstantiatedContainer*());
|
||||
MOCK_CONST_METHOD0(GetDataPatch, const AZ::DataPatch&());
|
||||
MOCK_CONST_METHOD0(GetDataFlags, const AZ::SliceComponent::DataFlagsPerEntity&());
|
||||
MOCK_METHOD0(GetDataFlags, AZ::SliceComponent::DataFlagsPerEntity&());
|
||||
MOCK_CONST_METHOD0(GetEntityIdMap, const AZ::SliceComponent::EntityIdToEntityIdMap& ());
|
||||
MOCK_CONST_METHOD0(GetEntityIdToBaseMap, const AZ::SliceComponent::EntityIdToEntityIdMap& ());
|
||||
MOCK_CONST_METHOD0(GetId, const AZ::SliceComponent::SliceInstanceId& ());
|
||||
MOCK_CONST_METHOD0(GetMetadataEntity, AZ::Entity* ());
|
||||
};
|
||||
|
||||
class MockEntity
|
||||
: public AZ::Entity
|
||||
{
|
||||
public:
|
||||
~MockEntity() override {}
|
||||
|
||||
MOCK_METHOD0(Init, void ());
|
||||
MOCK_METHOD0(Activate, void ());
|
||||
MOCK_METHOD0(Deactivate, void ());
|
||||
|
||||
/**
|
||||
* \brief Helper method for GoogleMock to call base class method
|
||||
*/
|
||||
void Base_Init()
|
||||
{
|
||||
Entity::Init();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Helper method for GoogleMock to mark an entity as activated
|
||||
*/
|
||||
void Base_Activate()
|
||||
{
|
||||
m_state = State::Active;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Helper method for GoogleMock to mark an entity as deactivated
|
||||
*/
|
||||
void Base_Deactivate()
|
||||
{
|
||||
m_state = State::Init;
|
||||
}
|
||||
};
|
||||
|
||||
class MockComponentApplication
|
||||
: public AZ::ComponentApplicationBus::Handler
|
||||
{
|
||||
public:
|
||||
MockComponentApplication()
|
||||
{
|
||||
AZ::ComponentApplicationBus::Handler::BusConnect();
|
||||
AZ::Interface<AZ::ComponentApplicationRequests>::Register(this);
|
||||
}
|
||||
~MockComponentApplication()
|
||||
{
|
||||
AZ::Interface<AZ::ComponentApplicationRequests>::Unregister(this);
|
||||
AZ::ComponentApplicationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
AZStd::vector<AZ::Entity*> m_mockEntities;
|
||||
|
||||
bool AddEntity(AZ::Entity* entity) override
|
||||
{
|
||||
const auto it = AZStd::find(m_mockEntities.begin(), m_mockEntities.end(), entity);
|
||||
if (it == m_mockEntities.end())
|
||||
{
|
||||
m_mockEntities.push_back(entity);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::Entity* FindEntity(const AZ::EntityId& id) override
|
||||
{
|
||||
const auto it = AZStd::find_if(m_mockEntities.begin(), m_mockEntities.end(), [id](AZ::Entity* entity)
|
||||
{
|
||||
return entity->GetId() == id;
|
||||
});
|
||||
|
||||
if (it != m_mockEntities.end())
|
||||
{
|
||||
return *it;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOCK_METHOD0(Destroy, void ());
|
||||
MOCK_METHOD1(RegisterComponentDescriptor, void (const AZ::ComponentDescriptor*));
|
||||
MOCK_METHOD1(UnregisterComponentDescriptor, void (const AZ::ComponentDescriptor*));
|
||||
MOCK_METHOD1(RegisterEntityAddedEventHandler, void(AZ::EntityAddedEvent::Handler&));
|
||||
MOCK_METHOD1(RegisterEntityRemovedEventHandler, void(AZ::EntityRemovedEvent::Handler&));
|
||||
MOCK_METHOD1(RemoveEntity, bool (AZ::Entity*));
|
||||
MOCK_METHOD1(DeleteEntity, bool (const AZ::EntityId&));
|
||||
MOCK_METHOD1(GetEntityName, AZStd::string (const AZ::EntityId&));
|
||||
MOCK_METHOD1(EnumerateEntities, void (const ComponentApplicationRequests::EntityCallback&));
|
||||
MOCK_METHOD0(GetApplication, AZ::ComponentApplication* ());
|
||||
MOCK_METHOD0(GetSerializeContext, AZ::SerializeContext* ());
|
||||
MOCK_METHOD0(GetBehaviorContext, AZ::BehaviorContext* ());
|
||||
MOCK_METHOD0(GetJsonRegistrationContext, AZ::JsonRegistrationContext* ());
|
||||
MOCK_CONST_METHOD0(GetAppRoot, const char* ());
|
||||
MOCK_CONST_METHOD0(GetEngineRoot, const char* ());
|
||||
MOCK_CONST_METHOD0(GetExecutableFolder, const char* ());
|
||||
MOCK_METHOD0(GetDrillerManager, AZ::Debug::DrillerManager* ());
|
||||
MOCK_METHOD0(GetTickDeltaTime, float ());
|
||||
MOCK_METHOD0(GetTimeAtCurrentTick, AZ::ScriptTimePoint ());
|
||||
MOCK_METHOD1(Tick, void (float));
|
||||
MOCK_METHOD0(TickSystem, void ());
|
||||
MOCK_CONST_METHOD0(GetRequiredSystemComponents, AZ::ComponentTypeList ());
|
||||
MOCK_METHOD1(ResolveModulePath, void (AZ::OSString&));
|
||||
MOCK_METHOD0(RegisterCoreComponents, void ());
|
||||
MOCK_METHOD1(Reflect, void (AZ::ReflectContext*));
|
||||
MOCK_CONST_METHOD1(QueryApplicationType, void(AZ::ApplicationTypeQuery&));
|
||||
};
|
||||
|
||||
class MockBindingComponent
|
||||
: public AZ::Component
|
||||
, public AzFramework::NetBindingHandlerBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(MockBindingComponent, "{8393809A-3256-4865-97A9-1CCA43073B4A}", NetBindingHandlerInterface);
|
||||
|
||||
static void Reflect(AZ::ReflectContext*) {}
|
||||
|
||||
MOCK_METHOD0(Init, void ());
|
||||
MOCK_METHOD0(Activate, void ());
|
||||
MOCK_METHOD0(Deactivate, void ());
|
||||
MOCK_METHOD1(ReadInConfig, bool (const AZ::ComponentConfig*));
|
||||
MOCK_CONST_METHOD1(WriteOutConfig, bool (AZ::ComponentConfig*));
|
||||
MOCK_METHOD1(BindToNetwork, void (GridMate::ReplicaPtr));
|
||||
MOCK_METHOD0(UnbindFromNetwork, void ());
|
||||
MOCK_METHOD0(IsEntityBoundToNetwork, bool ());
|
||||
MOCK_METHOD0(IsEntityAuthoritative, bool ());
|
||||
MOCK_METHOD0(MarkAsLevelSliceEntity, void ());
|
||||
MOCK_METHOD1(SetSliceInstanceId, void (const AZ::SliceComponent::SliceInstanceId&));
|
||||
MOCK_METHOD1(SetReplicaPriority, void (GridMate::ReplicaPriority));
|
||||
MOCK_METHOD1(RequestEntityChangeOwnership, void (GridMate::PeerId));
|
||||
MOCK_CONST_METHOD0(GetReplicaPriority, GridMate::ReplicaPriority ());
|
||||
};
|
||||
}
|
||||
|
||||
#endif // AZCORE_UNITTEST_NETBINDINGMOCKS_H
|
||||
@@ -1,605 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzFramework/Network/NetBindingSystemImpl.h>
|
||||
#include <AzFramework/Network/NetBindable.h>
|
||||
#include <AzFramework/Network/NetBindingSystemComponent.h>
|
||||
|
||||
#include <AzCore/Asset/AssetManagerComponent.h>
|
||||
#include <AzCore/Memory/AllocationRecords.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <GridMate/Serialize/CompressionMarshal.h>
|
||||
#include <GridMate/Replica/ReplicaFunctions.h>
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
#include "NetBindingMocks.h"
|
||||
#include <gmock/gmock-matchers.h>
|
||||
#include <gmock/gmock-more-actions.h>
|
||||
#include <gmock/gmock-spec-builders.h>
|
||||
#include <AzCore/Slice/SliceComponent.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
using namespace AZ;
|
||||
using namespace AzFramework;
|
||||
using namespace GridMate;
|
||||
|
||||
class NetBindingWithSlicesTest
|
||||
: public ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
const NetBindingContextSequence k_fakeContextSeq = 1;
|
||||
const AZ::SliceComponent::SliceInstanceId k_fakeSliceInstanceId = Uuid::CreateRandom();
|
||||
const AZ::SliceComponent::SliceInstanceId k_fakeSliceInstanceId_Another = Uuid::CreateRandom();
|
||||
|
||||
SliceInstantiationTicket m_sliceTicket = SliceInstantiationTicket(EntityContextId::CreateName("Test"), 1);
|
||||
const Data::AssetId k_fakeAssetId = Data::AssetId(Uuid::CreateRandom(), 0);
|
||||
|
||||
const EntityId k_fakeEntityId_One = EntityId(9001);
|
||||
const ReplicaId k_repId_One = 1001;
|
||||
const EntityId k_fakeEntityId_Two = EntityId(9002);
|
||||
const ReplicaId k_repId_Two = 1002;
|
||||
|
||||
AZStd::unique_ptr<NetBindingSystemImpl> m_netBindingImpl;
|
||||
AZStd::unique_ptr<MockComponentApplication> m_componentApplication;
|
||||
AZStd::unique_ptr<SerializeContext> m_applicationContext;
|
||||
|
||||
AZStd::unique_ptr<MockGameEntityContext> m_gameEntityMock;
|
||||
AZStd::unique_ptr<MockReplicaManager> m_replicaManagerMock;
|
||||
ReplicaPtr m_replicaMock;
|
||||
|
||||
ComponentDescriptor* m_netBindingSystemComponentDescriptor = nullptr;
|
||||
|
||||
AZStd::intrusive_ptr<MockNetBindingSystemContextData> m_contextChunkMock;
|
||||
|
||||
MockAssetHandler* m_myAssetHandlerAndCatalog = nullptr; // owned by AssetManager
|
||||
AZStd::unique_ptr<MockAsset> m_fakeAsset;
|
||||
|
||||
const float k_wayOverSliceTimeout = NetBindingSystemImpl::s_sliceBindingTimeout.count() * 2.f;
|
||||
const float k_smallStep = 0.1f;
|
||||
|
||||
void SetUpFakeAssetManager()
|
||||
{
|
||||
using namespace testing;
|
||||
|
||||
const Data::AssetManager::Descriptor desc;
|
||||
Data::AssetManager::Create(desc);
|
||||
|
||||
m_myAssetHandlerAndCatalog = aznew NiceMock<MockAssetHandler>;
|
||||
|
||||
ON_CALL(*m_myAssetHandlerAndCatalog, CreateAsset(_, _))
|
||||
.WillByDefault(Invoke([this](const Data::AssetId&, const Data::AssetType&) -> Data::AssetPtr
|
||||
{
|
||||
m_fakeAsset = AZStd::make_unique<NiceMock<MockAsset>>(k_fakeAssetId);
|
||||
return m_fakeAsset.get();
|
||||
}));
|
||||
|
||||
ON_CALL(*m_myAssetHandlerAndCatalog, DestroyAsset(_))
|
||||
.WillByDefault(Invoke([this](const Data::AssetPtr asset)
|
||||
{
|
||||
EXPECT_EQ(asset, m_fakeAsset.get());
|
||||
m_fakeAsset.reset();
|
||||
}));
|
||||
|
||||
Data::AssetManager::Instance().RegisterHandler(m_myAssetHandlerAndCatalog, AzTypeInfo<DynamicSliceAsset>::Uuid());
|
||||
Data::AssetManager::Instance().RegisterHandler(m_myAssetHandlerAndCatalog, AzTypeInfo<MockAsset>::Uuid());
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
using namespace testing;
|
||||
|
||||
m_applicationContext.reset(aznew SerializeContext());
|
||||
|
||||
AllocatorInstance<GridMateAllocatorMP>::Create();
|
||||
AllocatorInstance<ThreadPoolAllocator>::Create();
|
||||
|
||||
DefaultValue<SliceInstantiationTicket>::Set(m_sliceTicket);
|
||||
|
||||
m_gameEntityMock = AZStd::make_unique<NiceMock<MockGameEntityContext>>();
|
||||
m_componentApplication = AZStd::make_unique<NiceMock<MockComponentApplication>>();
|
||||
|
||||
ON_CALL(*m_componentApplication, GetSerializeContext())
|
||||
.WillByDefault(Invoke([this]()
|
||||
{
|
||||
return m_applicationContext.get();
|
||||
}));
|
||||
|
||||
ON_CALL(*m_gameEntityMock, GetGameEntityContextId())
|
||||
.WillByDefault(Return(EntityContextId::CreateRandom()));
|
||||
|
||||
m_netBindingSystemComponentDescriptor = NetBindingSystemComponent::CreateDescriptor();
|
||||
|
||||
ReplicaChunkDescriptorTable::Get().RegisterChunkType<MockNetBindingSystemContextData>();
|
||||
m_contextChunkMock.reset(CreateReplicaChunk<NiceMock<MockNetBindingSystemContextData>>());
|
||||
|
||||
ON_CALL(*m_contextChunkMock, ShouldBindToNetwork())
|
||||
.WillByDefault(Return(true));
|
||||
|
||||
m_replicaManagerMock = AZStd::make_unique<NiceMock<MockReplicaManager>>();
|
||||
|
||||
ON_CALL(*m_contextChunkMock, GetReplicaManager())
|
||||
.WillByDefault(Invoke([this]()
|
||||
{
|
||||
return m_replicaManagerMock.get();
|
||||
}));
|
||||
|
||||
m_replicaMock = Replica::CreateReplica("unittest");
|
||||
|
||||
ON_CALL(*m_replicaManagerMock, FindReplica(_))
|
||||
.WillByDefault(Invoke([this](ReplicaId id) -> ReplicaPtr
|
||||
{
|
||||
AZ_UNUSED(id);
|
||||
return m_replicaMock;
|
||||
}));
|
||||
|
||||
ON_CALL(*m_contextChunkMock, OnReplicaActivate(_))
|
||||
.WillByDefault(Invoke(m_contextChunkMock.get(), &MockNetBindingSystemContextData::Base_OnReplicaActivate));
|
||||
|
||||
m_netBindingImpl = AZStd::make_unique<AzFramework::NetBindingSystemImpl>();
|
||||
m_netBindingImpl->Init();
|
||||
|
||||
m_contextChunkMock->OnReplicaActivate(ReplicaContext(nullptr, TimeContext()));
|
||||
|
||||
SetUpFakeAssetManager();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
Data::AssetManager::Destroy();
|
||||
|
||||
m_replicaMock.reset();
|
||||
m_replicaManagerMock.reset();
|
||||
m_contextChunkMock.reset();
|
||||
|
||||
m_fakeAsset.reset();
|
||||
m_netBindingImpl->Shutdown();
|
||||
m_netBindingImpl.reset();
|
||||
|
||||
ReplicaChunkDescriptorTable::Get().UnregisterReplicaChunkDescriptor(ReplicaChunkClassId(MockNetBindingSystemContextData::GetChunkName()));
|
||||
|
||||
m_netBindingSystemComponentDescriptor->ReleaseDescriptor();
|
||||
|
||||
m_componentApplication.reset();
|
||||
m_gameEntityMock.reset();
|
||||
|
||||
AllocatorInstance<GridMateAllocatorMP>::Destroy();
|
||||
AllocatorInstance<ThreadPoolAllocator>::Destroy();
|
||||
|
||||
m_applicationContext.reset();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(NetBindingWithSlicesTest, SameSliceInstanceId_InstantiateDynamicSlice_CallOnce)
|
||||
{
|
||||
using namespace testing;
|
||||
|
||||
EXPECT_CALL(*m_gameEntityMock, InstantiateDynamicSlice(_, _, _))
|
||||
.Times(1);
|
||||
EXPECT_CALL(*m_gameEntityMock, CancelDynamicSliceInstantiation(_))
|
||||
.Times(1);
|
||||
|
||||
{
|
||||
NetBindingSliceContext spawnContext;
|
||||
spawnContext.m_contextSequence = k_fakeContextSeq;
|
||||
spawnContext.m_sliceAssetId = k_fakeAssetId;
|
||||
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_staticEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId; // both mock entities come from the same slice
|
||||
|
||||
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
|
||||
}
|
||||
{
|
||||
NetBindingSliceContext spawnContext;
|
||||
spawnContext.m_contextSequence = k_fakeContextSeq;
|
||||
spawnContext.m_sliceAssetId = k_fakeAssetId;
|
||||
spawnContext.m_runtimeEntityId = k_fakeEntityId_Two;
|
||||
spawnContext.m_staticEntityId = k_fakeEntityId_Two;
|
||||
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId; // both mock entities come from the same slice
|
||||
|
||||
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_Two, spawnContext);
|
||||
}
|
||||
|
||||
// this should kick off NetBindingSystemImpl::ProcessBindRequests
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
|
||||
}
|
||||
|
||||
TEST_F(NetBindingWithSlicesTest, DifferentSliceInstanceId_InstantiateDynamicSlice_CalledTwice)
|
||||
{
|
||||
using namespace testing;
|
||||
|
||||
EXPECT_CALL(*m_gameEntityMock, InstantiateDynamicSlice(_, _, _))
|
||||
.Times(2);
|
||||
EXPECT_CALL(*m_gameEntityMock, CancelDynamicSliceInstantiation(_))
|
||||
.Times(2);
|
||||
|
||||
{
|
||||
NetBindingSliceContext spawnContext;
|
||||
spawnContext.m_contextSequence = k_fakeContextSeq;
|
||||
spawnContext.m_sliceAssetId = k_fakeAssetId;
|
||||
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_staticEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId;
|
||||
|
||||
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
|
||||
}
|
||||
{
|
||||
NetBindingSliceContext spawnContext;
|
||||
spawnContext.m_contextSequence = k_fakeContextSeq;
|
||||
spawnContext.m_sliceAssetId = k_fakeAssetId;
|
||||
spawnContext.m_runtimeEntityId = k_fakeEntityId_Two;
|
||||
spawnContext.m_staticEntityId = k_fakeEntityId_Two;
|
||||
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId_Another; // different slice entity
|
||||
|
||||
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_Two, spawnContext);
|
||||
}
|
||||
|
||||
// this should kick off NetBindingSystemImpl::ProcessBindRequests
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
|
||||
}
|
||||
|
||||
TEST_F(NetBindingWithSlicesTest, AssetManagerDestroyed_InstantiateDynamicSlice_NotCalled)
|
||||
{
|
||||
{
|
||||
NetBindingSliceContext spawnContext;
|
||||
spawnContext.m_contextSequence = k_fakeContextSeq;
|
||||
spawnContext.m_sliceAssetId = k_fakeAssetId;
|
||||
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_staticEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId; // both mock entities come from the same slice
|
||||
|
||||
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
|
||||
}
|
||||
|
||||
Data::AssetManager::Destroy();
|
||||
|
||||
// this should kick off NetBindingSystemImpl::ProcessBindRequests, but InstantiateDynamicSlice will not be called
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
|
||||
}
|
||||
|
||||
class ExtendedBindingWithSlicesTest
|
||||
: public NetBindingWithSlicesTest
|
||||
{
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
NetBindingWithSlicesTest::SetUp();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
using namespace testing;
|
||||
|
||||
EXPECT_CALL(*m_gameEntityMock, DestroyGameEntity(k_fakeEntityId_One))
|
||||
.Times(AtMost(1));
|
||||
EXPECT_CALL(*m_gameEntityMock, DestroyGameEntity(k_fakeEntityId_Two))
|
||||
.Times(AtMost(1));
|
||||
|
||||
NetBindingWithSlicesTest::TearDown();
|
||||
}
|
||||
|
||||
class InstantiateMockSlice
|
||||
{
|
||||
public:
|
||||
explicit InstantiateMockSlice(ExtendedBindingWithSlicesTest* parent)
|
||||
{
|
||||
using namespace testing;
|
||||
|
||||
m_mockSliceRef = AZStd::make_unique<MockSliceReference>();
|
||||
m_mockSliceInstance = AZStd::make_unique<MockSliceInstance>();
|
||||
|
||||
// container owns the entities and will delete them
|
||||
auto mockContainer = AZStd::make_unique<SliceComponent::InstantiatedContainer>();
|
||||
|
||||
auto binding1 = AZStd::make_unique<NiceMock<MockBindingComponent>>();
|
||||
mockContainer->m_entities.push_back(CreateMockEntity(parent->k_fakeEntityId_One, binding1.release()));
|
||||
|
||||
auto binding2 = AZStd::make_unique<NiceMock<MockBindingComponent>>();
|
||||
mockContainer->m_entities.push_back(CreateMockEntity(parent->k_fakeEntityId_Two, binding2.release()));
|
||||
|
||||
m_mockSliceInstance->SetMockInstantiatedContainer(mockContainer.release());
|
||||
|
||||
SliceComponent::SliceInstanceAddress sliceInstanceAddress(m_mockSliceRef.get(), m_mockSliceInstance.get());
|
||||
|
||||
// This will pass our mock slice to NetBindingSystem
|
||||
EBUS_EVENT_ID(parent->m_sliceTicket, SliceInstantiationResultBus, OnSlicePreInstantiate, parent->k_fakeAssetId, sliceInstanceAddress);
|
||||
EBUS_EVENT_ID(parent->m_sliceTicket, SliceInstantiationResultBus, OnSliceInstantiated, parent->k_fakeAssetId, sliceInstanceAddress);
|
||||
}
|
||||
|
||||
Entity* CreateMockEntity(const EntityId& id, Component* optional = nullptr)
|
||||
{
|
||||
using namespace testing;
|
||||
|
||||
auto mock = AZStd::make_unique<NiceMock<MockEntity>>();
|
||||
mock->SetId(EntityId(id));
|
||||
if (optional)
|
||||
{
|
||||
mock->AddComponent(optional); // entity owns the component
|
||||
}
|
||||
ON_CALL(*mock, Init())
|
||||
.WillByDefault(Invoke(mock.get(), &MockEntity::Base_Init));
|
||||
mock->Init();
|
||||
|
||||
ON_CALL(*mock, Activate())
|
||||
.WillByDefault(Invoke(mock.get(), &MockEntity::Base_Activate));
|
||||
|
||||
ON_CALL(*mock, Deactivate())
|
||||
.WillByDefault(Invoke(mock.get(), &MockEntity::Base_Deactivate));
|
||||
|
||||
return mock.release();
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<MockSliceReference> m_mockSliceRef;
|
||||
AZStd::unique_ptr<MockSliceInstance> m_mockSliceInstance;
|
||||
};
|
||||
|
||||
AZStd::unique_ptr<InstantiateMockSlice> m_slice;
|
||||
|
||||
void CreateMockSlice()
|
||||
{
|
||||
m_slice = AZStd::make_unique<InstantiateMockSlice>(this);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ExtendedBindingWithSlicesTest, ActiveSlice_EntitiesThatWerentBounded_StayDeactivated)
|
||||
{
|
||||
{
|
||||
NetBindingSliceContext spawnContext;
|
||||
spawnContext.m_contextSequence = k_fakeContextSeq;
|
||||
spawnContext.m_sliceAssetId = k_fakeAssetId;
|
||||
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_staticEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId;
|
||||
|
||||
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
|
||||
}
|
||||
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
|
||||
CreateMockSlice();
|
||||
|
||||
MockEntity* mock1 = static_cast<MockEntity*>(m_componentApplication->FindEntity(k_fakeEntityId_One));
|
||||
EXPECT_CALL(*mock1, Activate()).
|
||||
Times(1);
|
||||
|
||||
MockEntity* mock2 = static_cast<MockEntity*>(m_componentApplication->FindEntity(k_fakeEntityId_Two));
|
||||
EXPECT_CALL(*mock2, Activate()).
|
||||
Times(0);
|
||||
|
||||
EXPECT_CALL(*m_gameEntityMock, DestroyGameEntity(k_fakeEntityId_Two))
|
||||
.Times(0);
|
||||
|
||||
// Now it should time out the slice handler and the second entity should remain deactivated since we didn't give binding request for it
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_wayOverSliceTimeout, AZ::ScriptTimePoint());
|
||||
|
||||
}
|
||||
|
||||
TEST_F(ExtendedBindingWithSlicesTest, ActiveSlice_SpawnSecondEntity_AfterLongDelay_InSameSlicenInstance)
|
||||
{
|
||||
EXPECT_CALL(*m_gameEntityMock, DestroyGameEntity(k_fakeEntityId_Two))
|
||||
.Times(0);
|
||||
|
||||
{
|
||||
NetBindingSliceContext spawnContext;
|
||||
spawnContext.m_contextSequence = k_fakeContextSeq;
|
||||
spawnContext.m_sliceAssetId = k_fakeAssetId;
|
||||
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_staticEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId;
|
||||
|
||||
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
|
||||
}
|
||||
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
|
||||
CreateMockSlice();
|
||||
|
||||
MockEntity* mock2 = static_cast<MockEntity*>(m_componentApplication->FindEntity(k_fakeEntityId_Two));
|
||||
EXPECT_CALL(*mock2, Activate()).
|
||||
Times(0);
|
||||
|
||||
// This should not trigger removal of the second entity yet
|
||||
auto halfTimeoutInSeconds = AZStd::chrono::seconds(NetBindingSystemImpl::s_sliceBindingTimeout).count() * 10.f;
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, halfTimeoutInSeconds, AZ::ScriptTimePoint());
|
||||
|
||||
{
|
||||
NetBindingSliceContext spawnContext;
|
||||
spawnContext.m_contextSequence = k_fakeContextSeq;
|
||||
spawnContext.m_sliceAssetId = k_fakeAssetId;
|
||||
spawnContext.m_runtimeEntityId = k_fakeEntityId_Two;
|
||||
spawnContext.m_staticEntityId = k_fakeEntityId_Two;
|
||||
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId; // both mock entities come from the same slice
|
||||
|
||||
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_Two, spawnContext);
|
||||
}
|
||||
|
||||
EXPECT_CALL(*mock2, Activate()).
|
||||
Times(1);
|
||||
|
||||
// This should give net binding system time to bind the second entity
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
|
||||
|
||||
// Let the slice timeout, this should lead to no destruction since both entities ought to have been bound by now
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_wayOverSliceTimeout, AZ::ScriptTimePoint());
|
||||
}
|
||||
|
||||
TEST_F(ExtendedBindingWithSlicesTest, ActiveSlice_DespawnLastEntity_DespawnWholeSliceAfterTimeout)
|
||||
{
|
||||
{
|
||||
NetBindingSliceContext spawnContext;
|
||||
spawnContext.m_contextSequence = k_fakeContextSeq;
|
||||
spawnContext.m_sliceAssetId = k_fakeAssetId;
|
||||
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_staticEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId;
|
||||
|
||||
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
|
||||
}
|
||||
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
|
||||
CreateMockSlice();
|
||||
|
||||
MockEntity* mock1 = static_cast<MockEntity*>(m_componentApplication->FindEntity(k_fakeEntityId_One));
|
||||
EXPECT_CALL(*mock1, Activate()).
|
||||
Times(1);
|
||||
|
||||
// This should not trigger removal of the second entity yet
|
||||
auto halfTimeoutInSeconds = AZStd::chrono::seconds(NetBindingSystemImpl::s_sliceBindingTimeout).count() * 10.f;
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, halfTimeoutInSeconds, AZ::ScriptTimePoint());
|
||||
|
||||
EXPECT_CALL(*mock1, Deactivate()).
|
||||
Times(1);
|
||||
EBUS_EVENT(NetBindingSystemBus, UnbindGameEntity, k_fakeEntityId_One, k_fakeSliceInstanceId);
|
||||
|
||||
EXPECT_CALL(*m_gameEntityMock, DestroyGameEntity(k_fakeEntityId_One))
|
||||
.Times(1);
|
||||
EXPECT_CALL(*m_gameEntityMock, DestroyGameEntity(k_fakeEntityId_Two))
|
||||
.Times(1);
|
||||
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_wayOverSliceTimeout, AZ::ScriptTimePoint());
|
||||
}
|
||||
|
||||
TEST_F(ExtendedBindingWithSlicesTest, ActiveSlice_DespawnLastEntityBeforeSliceInstantiation_DespawnWholeSlice)
|
||||
{
|
||||
{
|
||||
NetBindingSliceContext spawnContext;
|
||||
spawnContext.m_contextSequence = k_fakeContextSeq;
|
||||
spawnContext.m_sliceAssetId = k_fakeAssetId;
|
||||
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_staticEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId;
|
||||
|
||||
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
|
||||
}
|
||||
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
|
||||
|
||||
EBUS_EVENT(NetBindingSystemBus, UnbindGameEntity, k_fakeEntityId_One, k_fakeSliceInstanceId);
|
||||
|
||||
CreateMockSlice();
|
||||
|
||||
MockEntity* mock1 = static_cast<MockEntity*>(m_componentApplication->FindEntity(k_fakeEntityId_One));
|
||||
EXPECT_CALL(*mock1, Activate()).
|
||||
Times(0);
|
||||
|
||||
auto halfTimeoutInSeconds = AZStd::chrono::seconds(NetBindingSystemImpl::s_sliceBindingTimeout).count() * 10.f;
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, halfTimeoutInSeconds, AZ::ScriptTimePoint());
|
||||
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_wayOverSliceTimeout, AZ::ScriptTimePoint());
|
||||
}
|
||||
|
||||
TEST_F(ExtendedBindingWithSlicesTest, ActiveSlice_ReuseEntity)
|
||||
{
|
||||
EXPECT_CALL(*m_gameEntityMock, DestroyGameEntity(k_fakeEntityId_Two))
|
||||
.Times(0);
|
||||
|
||||
{
|
||||
NetBindingSliceContext spawnContext;
|
||||
spawnContext.m_contextSequence = k_fakeContextSeq;
|
||||
spawnContext.m_sliceAssetId = k_fakeAssetId;
|
||||
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_staticEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId;
|
||||
|
||||
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
|
||||
}
|
||||
{
|
||||
NetBindingSliceContext spawnContext;
|
||||
spawnContext.m_contextSequence = k_fakeContextSeq;
|
||||
spawnContext.m_sliceAssetId = k_fakeAssetId;
|
||||
spawnContext.m_runtimeEntityId = k_fakeEntityId_Two;
|
||||
spawnContext.m_staticEntityId = k_fakeEntityId_Two;
|
||||
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId; // both mock entities come from the same slice
|
||||
|
||||
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_Two, spawnContext);
|
||||
}
|
||||
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
|
||||
CreateMockSlice();
|
||||
|
||||
MockEntity* mock2 = static_cast<MockEntity*>(m_componentApplication->FindEntity(k_fakeEntityId_Two));
|
||||
EXPECT_CALL(*mock2, Activate()).
|
||||
Times(1);
|
||||
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_wayOverSliceTimeout, AZ::ScriptTimePoint());
|
||||
|
||||
EXPECT_CALL(*mock2, Deactivate()).
|
||||
Times(1);
|
||||
|
||||
// some time later the second entity goes away and comes back
|
||||
EBUS_EVENT(NetBindingSystemBus, UnbindGameEntity, k_fakeEntityId_Two, k_fakeSliceInstanceId);
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
|
||||
|
||||
{
|
||||
NetBindingSliceContext spawnContext;
|
||||
spawnContext.m_contextSequence = k_fakeContextSeq;
|
||||
spawnContext.m_sliceAssetId = k_fakeAssetId;
|
||||
spawnContext.m_runtimeEntityId = k_fakeEntityId_Two;
|
||||
spawnContext.m_staticEntityId = k_fakeEntityId_Two;
|
||||
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId; // both mock entities come from the same slice
|
||||
|
||||
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_Two, spawnContext);
|
||||
}
|
||||
|
||||
// The same entity should be activated for the second time
|
||||
EXPECT_CALL(*mock2, Activate()).
|
||||
Times(1); // Note, Google Mock treats each expect_call separately and satisfies them separately. That's why it's 1 here, despite being a second call.
|
||||
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
|
||||
}
|
||||
|
||||
TEST_F(ExtendedBindingWithSlicesTest, SliceFailedToSpawn)
|
||||
{
|
||||
{
|
||||
NetBindingSliceContext spawnContext;
|
||||
spawnContext.m_contextSequence = k_fakeContextSeq;
|
||||
spawnContext.m_sliceAssetId = k_fakeAssetId;
|
||||
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_staticEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId;
|
||||
|
||||
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
|
||||
}
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
|
||||
|
||||
EBUS_EVENT_ID(m_sliceTicket, SliceInstantiationResultBus, OnSliceInstantiationFailed, k_fakeAssetId);
|
||||
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
|
||||
|
||||
EXPECT_TRUE(m_componentApplication->FindEntity(k_fakeEntityId_One) == nullptr);
|
||||
}
|
||||
|
||||
TEST_F(ExtendedBindingWithSlicesTest, SliceSpawned_AfterTimeout)
|
||||
{
|
||||
{
|
||||
NetBindingSliceContext spawnContext;
|
||||
spawnContext.m_contextSequence = k_fakeContextSeq;
|
||||
spawnContext.m_sliceAssetId = k_fakeAssetId;
|
||||
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_staticEntityId = k_fakeEntityId_One;
|
||||
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId;
|
||||
|
||||
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
|
||||
}
|
||||
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_wayOverSliceTimeout, AZ::ScriptTimePoint());
|
||||
|
||||
CreateMockSlice();
|
||||
|
||||
MockEntity* mock1 = static_cast<MockEntity*>(m_componentApplication->FindEntity(k_fakeEntityId_One));
|
||||
EXPECT_CALL(*mock1, Activate()).
|
||||
Times(1);
|
||||
|
||||
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
|
||||
}
|
||||
}
|
||||
@@ -1,801 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzFramework/Network/NetworkContext.h>
|
||||
#include <AzFramework/Application/Application.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzCore/Memory/MemoryComponent.h>
|
||||
#include <AzCore/Serialization/Utils.h>
|
||||
#include <AzCore/IO/ByteContainerStream.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/UserSettings/UserSettingsComponent.h>
|
||||
|
||||
#include <GridMate/Replica/ReplicaChunk.h>
|
||||
#include <GridMate/Replica/DataSet.h>
|
||||
#include <GridMate/Replica/RemoteProcedureCall.h>
|
||||
#include <GridMate/Serialize/DataMarshal.h>
|
||||
#include <GridMate/Serialize/UtilityMarshal.h>
|
||||
#include <GridMate/Serialize/ContainerMarshal.h>
|
||||
#include <GridMate/Replica/ReplicaMgr.h>
|
||||
#include <AzFramework/Network/InterestManagerComponent.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
using namespace AZ;
|
||||
using namespace AzFramework;
|
||||
|
||||
class TestComponentExternalChunk
|
||||
: public AZ::Component
|
||||
, public NetBindable
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(TestComponentExternalChunk, "{73BB3B15-7C4D-4BD5-9568-F3B2DCBC7725}", AZ::Component);
|
||||
|
||||
static void Reflect(ReflectContext* context);
|
||||
|
||||
void Init() override
|
||||
{
|
||||
NetBindable::NetInit();
|
||||
}
|
||||
|
||||
void Activate() override {}
|
||||
void Deactivate() override {}
|
||||
|
||||
bool SetPos(float x, float y, const RpcContext&)
|
||||
{
|
||||
m_x = x;
|
||||
m_y = y;
|
||||
return true;
|
||||
}
|
||||
|
||||
void OnFloatChanged(const float&, const TimeContext&)
|
||||
{
|
||||
m_floatChanged = true;
|
||||
}
|
||||
|
||||
bool m_floatChanged = false;
|
||||
private:
|
||||
float m_x = 0, m_y = 0;
|
||||
};
|
||||
|
||||
class TestComponentReplicaChunk
|
||||
: public ReplicaChunkBase
|
||||
, public ReplicaChunkInterface
|
||||
{
|
||||
public:
|
||||
GM_CLASS_ALLOCATOR(TestComponentReplicaChunk);
|
||||
static const char* GetChunkName() { return "TestComponentReplicaChunk"; }
|
||||
bool IsReplicaMigratable() override { return true; }
|
||||
|
||||
public:
|
||||
TestComponentReplicaChunk()
|
||||
: m_int("m_int", 42)
|
||||
, m_float("m_float", 96.4f)
|
||||
, SetInt("SetInt")
|
||||
, SetPos("SetPos")
|
||||
{
|
||||
}
|
||||
|
||||
bool SetIntImpl(int newValue, const RpcContext&)
|
||||
{
|
||||
m_int.Set(newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
DataSet<int> m_int;
|
||||
DataSet<float>::BindInterface<TestComponentExternalChunk, &TestComponentExternalChunk::OnFloatChanged> m_float;
|
||||
GridMate::Rpc<GridMate::RpcArg<int, Marshaler<int> > >::BindInterface<TestComponentReplicaChunk, &TestComponentReplicaChunk::SetIntImpl> SetInt;
|
||||
GridMate::Rpc<GridMate::RpcArg<float>, GridMate::RpcArg<float> >::BindInterface<TestComponentExternalChunk, &TestComponentExternalChunk::SetPos> SetPos;
|
||||
};
|
||||
|
||||
void TestComponentExternalChunk::Reflect(ReflectContext* context)
|
||||
{
|
||||
NetworkContext* netContext = azrtti_cast<NetworkContext*>(context);
|
||||
if (netContext)
|
||||
{
|
||||
netContext->Class<TestComponentExternalChunk>()
|
||||
->Chunk<TestComponentReplicaChunk>()
|
||||
->Field("m_int", &TestComponentReplicaChunk::m_int)
|
||||
->Field("m_float", &TestComponentReplicaChunk::m_float)
|
||||
->RPC("SetInt", &TestComponentReplicaChunk::SetInt)
|
||||
->RPC("SetPos", &TestComponentReplicaChunk::SetPos);
|
||||
}
|
||||
}
|
||||
|
||||
class TestComponentAutoChunk
|
||||
: public AZ::Component
|
||||
, public NetBindable
|
||||
{
|
||||
public:
|
||||
enum TestEnum
|
||||
{
|
||||
TEST_Value0 = 0,
|
||||
TEST_Value1 = 1,
|
||||
TEST_Value255 = 255
|
||||
};
|
||||
|
||||
AZ_COMPONENT(TestComponentAutoChunk, "{003FD1BC-8456-43D5-9879-1B3804327A4F}", AZ::Component);
|
||||
|
||||
static void Reflect(ReflectContext* context)
|
||||
{
|
||||
NetworkContext* netContext = azrtti_cast<NetworkContext*>(context);
|
||||
if (netContext)
|
||||
{
|
||||
netContext->Class<TestComponentAutoChunk>()
|
||||
->Field("m_int", &TestComponentAutoChunk::m_int)
|
||||
->Field("m_float", &TestComponentAutoChunk::m_float)
|
||||
->Field("m_enum", &TestComponentAutoChunk::m_enum)
|
||||
->RPC("SetInt", &TestComponentAutoChunk::SetInt)
|
||||
->CtorData("CtorInt", &TestComponentAutoChunk::GetCtorInt, &TestComponentAutoChunk::SetCtorInt)
|
||||
->CtorData("CtorVec", &TestComponentAutoChunk::GetCtorVec, &TestComponentAutoChunk::SetCtorVec);
|
||||
}
|
||||
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
|
||||
if (serializeContext)
|
||||
{
|
||||
serializeContext->Class<TestComponentAutoChunk, AZ::Component>()
|
||||
->Version(1)
|
||||
->Field("m_int", &TestComponentAutoChunk::m_int)
|
||||
->Field("m_float", &TestComponentAutoChunk::m_float)
|
||||
->Field("m_enum", &TestComponentAutoChunk::m_enum)
|
||||
->Field("ctorInt", &TestComponentAutoChunk::m_ctorInt)
|
||||
->Field("ctorVec", &TestComponentAutoChunk::m_ctorVec);
|
||||
}
|
||||
}
|
||||
|
||||
void Init() override
|
||||
{
|
||||
NetBindable::NetInit();
|
||||
}
|
||||
|
||||
void Activate() override {}
|
||||
void Deactivate() override {}
|
||||
|
||||
void SetNetworkBinding(ReplicaChunkPtr chunk) override {}
|
||||
void UnbindFromNetwork() override {}
|
||||
|
||||
bool SetIntImpl(int val, const RpcContext&)
|
||||
{
|
||||
m_int = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
void OnFloatChanged(const float&, const TimeContext&)
|
||||
{
|
||||
}
|
||||
|
||||
int GetCtorInt() const { return m_ctorInt; }
|
||||
void SetCtorInt(const int& ctorInt) { m_ctorInt = ctorInt; }
|
||||
|
||||
AZStd::vector<int>& GetCtorVec() { return m_ctorVec; }
|
||||
void SetCtorVec(const AZStd::vector<int>& vec) { m_ctorVec = vec; }
|
||||
|
||||
int m_ctorInt;
|
||||
AZStd::vector<int> m_ctorVec;
|
||||
Field<int> m_int;
|
||||
BoundField<float, TestComponentAutoChunk, &TestComponentAutoChunk::OnFloatChanged> m_float;
|
||||
Field<TestEnum, GridMate::ConversionMarshaler<AZ::u8, TestEnum> > m_enum;
|
||||
Rpc<int>::Binder<TestComponentAutoChunk, &TestComponentAutoChunk::SetIntImpl> SetInt;
|
||||
};
|
||||
|
||||
class NetContextReflectionTest
|
||||
: public AllocatorsTestFixture
|
||||
{
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
AllocatorsTestFixture::SetUp();
|
||||
|
||||
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Create();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Destroy();
|
||||
|
||||
AllocatorsTestFixture::TearDown();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
AzFramework::Application app;
|
||||
AzFramework::Application::Descriptor appDesc;
|
||||
appDesc.m_recordingMode = Debug::AllocationRecords::RECORD_NO_RECORDS;
|
||||
appDesc.m_allocationRecords = false;
|
||||
appDesc.m_enableDrilling = false;
|
||||
|
||||
app.Start(appDesc);
|
||||
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
// in the unit tests.
|
||||
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
|
||||
|
||||
AzFramework::NetworkContext* netContext = nullptr;
|
||||
EBUS_EVENT_RESULT(netContext, NetSystemRequestBus, GetNetworkContext);
|
||||
AZ_TEST_ASSERT(netContext);
|
||||
|
||||
AZ::ComponentDescriptor* descTestComponentExternalChunk = TestComponentExternalChunk::CreateDescriptor();
|
||||
app.RegisterComponentDescriptor(descTestComponentExternalChunk);
|
||||
|
||||
AZ::ComponentDescriptor* descTestComponentAutoChunk = TestComponentAutoChunk::CreateDescriptor();
|
||||
app.RegisterComponentDescriptor(descTestComponentAutoChunk);
|
||||
|
||||
AZ::Entity* testEntity = aznew AZ::Entity("TestEntity");
|
||||
testEntity->Init();
|
||||
testEntity->CreateComponent<TestComponentAutoChunk>();
|
||||
testEntity->CreateComponent<TestComponentExternalChunk>();
|
||||
testEntity->Activate();
|
||||
|
||||
// test field binding/auto reflection/creation
|
||||
{
|
||||
TestComponentAutoChunk* testComponent = testEntity->FindComponent<TestComponentAutoChunk>();
|
||||
AZ_TEST_ASSERT(testComponent);
|
||||
|
||||
testComponent->SetInt(2048); // should happen locally
|
||||
AZ_TEST_ASSERT(testComponent->m_int == 2048);
|
||||
|
||||
ReplicaChunkPtr chunk = testComponent->GetNetworkBinding();
|
||||
AZ_TEST_ASSERT(chunk);
|
||||
|
||||
GridMate::ReplicaChunkDescriptor* desc = chunk->GetDescriptor();
|
||||
AZ_TEST_ASSERT(desc);
|
||||
|
||||
testComponent->m_ctorInt = 8192;
|
||||
for (int n = 0; n < 16; ++n)
|
||||
{
|
||||
testComponent->m_ctorVec.push_back(n);
|
||||
}
|
||||
|
||||
GridMate::WriteBufferDynamic wb(GridMate::EndianType::IgnoreEndian);
|
||||
desc->MarshalCtorData(chunk.get(), wb);
|
||||
|
||||
{
|
||||
// Create a chunk from the recorded ctor data, ensure that it stores
|
||||
// the ctor data in preparation for copying it to the instance
|
||||
GridMate::TimeContext tc;
|
||||
GridMate::ReplicaContext rc(nullptr, tc);
|
||||
GridMate::ReadBuffer rb(wb.GetEndianType(), wb.Get(), wb.Size());
|
||||
GridMate::UnmarshalContext ctx(rc);
|
||||
ctx.m_hasCtorData = true;
|
||||
ctx.m_iBuf = &rb;
|
||||
ReplicaChunkPtr chunk2 = desc->CreateFromStream(ctx);
|
||||
AZ_TEST_ASSERT(chunk2); // ensure a new chunk was created
|
||||
ReflectedReplicaChunkBase* refChunk = static_cast<ReflectedReplicaChunkBase*>(chunk2.get());
|
||||
AZ_TEST_ASSERT(refChunk->m_ctorBuffer.Size() == sizeof(int) + sizeof(AZ::u16) + (sizeof(int) * testComponent->m_ctorVec.size()));
|
||||
}
|
||||
|
||||
{
|
||||
// discard a ctor data stream and ensure that the stream is emptied
|
||||
GridMate::TimeContext tc;
|
||||
GridMate::ReplicaContext rc(nullptr, tc);
|
||||
GridMate::ReadBuffer rb(wb.GetEndianType(), wb.Get(), wb.Size());
|
||||
GridMate::UnmarshalContext ctx(rc);
|
||||
ctx.m_hasCtorData = true;
|
||||
ctx.m_iBuf = &rb;
|
||||
desc->DiscardCtorStream(ctx);
|
||||
AZ_TEST_ASSERT(rb.IsEmptyIgnoreTrailingBits()); // should have discarded the whole stream
|
||||
}
|
||||
|
||||
{
|
||||
// Make another chunk and bind it to a new component and make sure the ctor data matches
|
||||
AZ::Entity* testEntity2 = aznew AZ::Entity("TestEntity2");
|
||||
testEntity2->Init();
|
||||
testEntity2->CreateComponent<TestComponentAutoChunk>();
|
||||
testEntity2->Activate();
|
||||
|
||||
GridMate::TimeContext tc;
|
||||
GridMate::ReplicaContext rc(nullptr, tc);
|
||||
GridMate::ReadBuffer rb(wb.GetEndianType(), wb.Get(), wb.Size());
|
||||
GridMate::UnmarshalContext ctx(rc);
|
||||
ctx.m_hasCtorData = true;
|
||||
ctx.m_iBuf = &rb;
|
||||
ReplicaChunkPtr chunk2 = desc->CreateFromStream(ctx);
|
||||
|
||||
TestComponentAutoChunk* testComponent2 = testEntity2->FindComponent<TestComponentAutoChunk>();
|
||||
netContext->Bind(testComponent2, chunk2, NetworkContextBindMode::NonAuthoritative);
|
||||
// Ensure values match after ctor data is applied
|
||||
AZ_TEST_ASSERT(testComponent2->m_ctorInt == testComponent->m_ctorInt);
|
||||
AZ_TEST_ASSERT(testComponent2->m_ctorVec == testComponent->m_ctorVec);
|
||||
}
|
||||
|
||||
testComponent->SetInt(4096);
|
||||
AZ_TEST_ASSERT(testComponent->m_int == 4096);
|
||||
|
||||
testComponent->m_int = 42; // now it should change
|
||||
AZ_TEST_ASSERT(testComponent->m_int == 42);
|
||||
testComponent->m_enum = TestComponentAutoChunk::TEST_Value1;
|
||||
|
||||
chunk.reset(); // should cause netContext->DestroyReplicaChunk()
|
||||
}
|
||||
|
||||
// test chunk binding/creation
|
||||
{
|
||||
TestComponentExternalChunk* testComponent = testEntity->FindComponent<TestComponentExternalChunk>();
|
||||
AZ_TEST_ASSERT(testComponent);
|
||||
|
||||
ReplicaChunkPtr chunk = testComponent->GetNetworkBinding();
|
||||
AZ_TEST_ASSERT(chunk);
|
||||
|
||||
TestComponentReplicaChunk* testChunk = static_cast<TestComponentReplicaChunk*>(chunk.get());
|
||||
|
||||
// for now, this will throw a warning, but will at least attempt the dispatch
|
||||
testChunk->SetPos(42.0f, 96.0f);
|
||||
|
||||
AZ_TEST_ASSERT(testComponent->m_floatChanged == false);
|
||||
testChunk->m_float.Set(1024.0f);
|
||||
// I would like to test that the notify fired, but without a Replica, cant :(
|
||||
|
||||
testComponent->UnbindFromNetwork();
|
||||
chunk.reset(); ///// CRASHES FROM HERE
|
||||
}
|
||||
|
||||
// test serialization of NetBindable::Fields
|
||||
{
|
||||
TestComponentAutoChunk* testComponent = testEntity->FindComponent<TestComponentAutoChunk>();
|
||||
AZStd::vector<AZ::u8> buffer;
|
||||
AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8> > saveStream(&buffer);
|
||||
bool saved = AZ::Utils::SaveObjectToStream(saveStream, AZ::DataStream::ST_XML, testComponent);
|
||||
AZ_TEST_ASSERT(saved);
|
||||
AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8> > loadStream(&buffer);
|
||||
TestComponentAutoChunk* testCopy = AZ::Utils::LoadObjectFromStream<TestComponentAutoChunk>(loadStream);
|
||||
AZ_TEST_ASSERT(testCopy);
|
||||
delete testCopy;
|
||||
}
|
||||
|
||||
testEntity->Deactivate();
|
||||
delete testEntity;
|
||||
|
||||
descTestComponentExternalChunk->ReleaseDescriptor();
|
||||
descTestComponentAutoChunk->ReleaseDescriptor();
|
||||
|
||||
app.Stop();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(NetContextReflectionTest, Test)
|
||||
{
|
||||
run();
|
||||
}
|
||||
|
||||
template <typename ComponentType>
|
||||
class NetContextFixture
|
||||
: public ::testing::Test
|
||||
{
|
||||
public:
|
||||
NetContextFixture() = default;
|
||||
~NetContextFixture() = default;
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
AZ::AllocatorInstance<SystemAllocator>::Create();
|
||||
|
||||
m_app = AZStd::make_unique<AzFramework::Application>();
|
||||
m_app->Start(AzFramework::Application::Descriptor());
|
||||
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
// in the unit tests.
|
||||
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
|
||||
|
||||
AzFramework::NetworkContext* netContext = nullptr;
|
||||
EBUS_EVENT_RESULT(netContext, NetSystemRequestBus, GetNetworkContext);
|
||||
AZ_TEST_ASSERT(netContext);
|
||||
|
||||
m_descTestComponentAutoChunk = ComponentType::CreateDescriptor();
|
||||
m_app->RegisterComponentDescriptor(m_descTestComponentAutoChunk);
|
||||
|
||||
m_entity = AZStd::make_unique<AZ::Entity>("TestEntity");
|
||||
m_entity->Init();
|
||||
m_entity->CreateComponent<ComponentType>();
|
||||
m_entity->Activate();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_descTestComponentAutoChunk->ReleaseDescriptor();
|
||||
|
||||
m_entity->Deactivate();
|
||||
m_entity.reset();
|
||||
|
||||
m_app->Stop();
|
||||
m_app.reset();
|
||||
|
||||
AZ::AllocatorInstance<SystemAllocator>::Destroy();
|
||||
}
|
||||
|
||||
void RunTest()
|
||||
{
|
||||
const ComponentType* testComponent = m_entity->FindComponent<ComponentType>();
|
||||
AZStd::vector<AZ::u8> buffer;
|
||||
AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8> > saveStream(&buffer);
|
||||
const bool saved = AZ::Utils::SaveObjectToStream(saveStream, AZ::DataStream::ST_XML, testComponent);
|
||||
AZ_TEST_ASSERT(saved);
|
||||
AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8> > loadStream(&buffer);
|
||||
const AZStd::unique_ptr<ComponentType> testCopy(AZ::Utils::LoadObjectFromStream<ComponentType>(loadStream));
|
||||
AZ_TEST_ASSERT(testCopy);
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AzFramework::Application> m_app;
|
||||
AZStd::unique_ptr<AZ::Entity> m_entity;
|
||||
AZ::ComponentDescriptor* m_descTestComponentAutoChunk = nullptr;
|
||||
};
|
||||
|
||||
class TestComponent_EmptyNetContext
|
||||
: public AZ::Component
|
||||
, public NetBindable
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(TestComponent_EmptyNetContext, "{B1E2E2DD-DA70-4D59-A185-AF9A5CCF1574}", AZ::Component, NetBindable);
|
||||
|
||||
static void Reflect(ReflectContext* context)
|
||||
{
|
||||
if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<TestComponent_EmptyNetContext, AZ::Component>()
|
||||
->Version(1);
|
||||
}
|
||||
if (NetworkContext* netContext = azrtti_cast<NetworkContext*>(context))
|
||||
{
|
||||
netContext->Class<TestComponent_EmptyNetContext>();
|
||||
}
|
||||
}
|
||||
|
||||
void Activate() override {}
|
||||
void Deactivate() override {}
|
||||
};
|
||||
|
||||
using NetContextEmpty = NetContextFixture<TestComponent_EmptyNetContext>;
|
||||
TEST_F(NetContextEmpty, SerializationTests)
|
||||
{
|
||||
RunTest();
|
||||
}
|
||||
|
||||
template<typename FieldType>
|
||||
class TestComponent_OneField
|
||||
: public AZ::Component
|
||||
, public NetBindable
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(TestComponent_OneField, "{A7BCDBEF-3D4F-4D04-A6FA-DF48D4B66ABE}", AZ::Component, NetBindable);
|
||||
|
||||
using ThisComponentType = TestComponent_OneField<FieldType>;
|
||||
|
||||
static void Reflect(ReflectContext* context)
|
||||
{
|
||||
if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<TestComponent_OneField, AZ::Component>()
|
||||
->Field("Field", &TestComponent_OneField::m_field)
|
||||
->Version(1);
|
||||
}
|
||||
if (NetworkContext* netContext = azrtti_cast<NetworkContext*>(context))
|
||||
{
|
||||
netContext->Class<TestComponent_OneField>()
|
||||
->Field("Field", &TestComponent_OneField::m_field);
|
||||
}
|
||||
}
|
||||
|
||||
void Activate() override {}
|
||||
void Deactivate() override {}
|
||||
|
||||
Field<FieldType> m_field;
|
||||
};
|
||||
|
||||
TYPED_TEST_CASE_P(NetContextFixture);
|
||||
|
||||
TYPED_TEST_P(NetContextFixture, SerializationTests)
|
||||
{
|
||||
this->RunTest();
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_CASE_P(NetContextFixture, SerializationTests);
|
||||
|
||||
/*
|
||||
* Testing the basic common types.
|
||||
*/
|
||||
using CommonTypes = ::testing::Types<
|
||||
TestComponent_OneField<bool>,
|
||||
TestComponent_OneField<float>,
|
||||
TestComponent_OneField<AZ::u32>,
|
||||
TestComponent_OneField<AZ::EntityId>,
|
||||
TestComponent_OneField<AZ::Vector2>,
|
||||
TestComponent_OneField<AZ::Vector3>,
|
||||
TestComponent_OneField<AZ::Quaternion>
|
||||
>;
|
||||
|
||||
INSTANTIATE_TYPED_TEST_CASE_P(NetContextCommonSerialization, NetContextFixture, CommonTypes);
|
||||
|
||||
/*
|
||||
* And some less common types.
|
||||
*/
|
||||
using LessCommonTypes = ::testing::Types<
|
||||
TestComponent_OneField<AZStd::string>,
|
||||
TestComponent_OneField<AZ::Transform>,
|
||||
TestComponent_OneField<AZ::Color>,
|
||||
TestComponent_OneField<AZStd::vector<int>>,
|
||||
TestComponent_OneField<AZ::Uuid>
|
||||
>;
|
||||
|
||||
INSTANTIATE_TYPED_TEST_CASE_P(NetContextLessCommonSerialization, NetContextFixture, LessCommonTypes);
|
||||
|
||||
/*
|
||||
* Next up are marshal and unmarshal tests.
|
||||
*/
|
||||
|
||||
template <typename ComponentType>
|
||||
class NetContextMarshalFixture
|
||||
: public UnitTest::AllocatorsTestFixture
|
||||
{
|
||||
public:
|
||||
NetContextMarshalFixture() = default;
|
||||
~NetContextMarshalFixture() = default;
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
UnitTest::AllocatorsTestFixture::SetUp();
|
||||
|
||||
AZ::AllocatorInstance<GridMate::GridMateAllocator>::Create();
|
||||
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Create();
|
||||
|
||||
m_app = AZStd::make_unique<AzFramework::Application>();
|
||||
m_app->Start(AzFramework::Application::Descriptor());
|
||||
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
// in the unit tests.
|
||||
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
|
||||
|
||||
AzFramework::NetworkContext* netContext = nullptr;
|
||||
EBUS_EVENT_RESULT(netContext, NetSystemRequestBus, GetNetworkContext);
|
||||
AZ_TEST_ASSERT(netContext);
|
||||
|
||||
m_descTestComponentAutoChunk = ComponentType::CreateDescriptor();
|
||||
m_app->RegisterComponentDescriptor(m_descTestComponentAutoChunk);
|
||||
|
||||
m_entityFrom = AZStd::make_unique<AZ::Entity>("TestEntityFrom");
|
||||
m_entityFrom->Init();
|
||||
m_componentFrom = m_entityFrom->CreateComponent<ComponentType>();
|
||||
m_entityFrom->Activate();
|
||||
|
||||
m_entityTo = AZStd::make_unique<AZ::Entity>("TestEntityTo");
|
||||
m_entityTo->Init();
|
||||
m_componentTo = m_entityTo->CreateComponent<ComponentType>();
|
||||
m_entityTo->Activate();
|
||||
}
|
||||
|
||||
void MarshalUnMarshal()
|
||||
{
|
||||
AzFramework::NetworkContext* netContext = nullptr;
|
||||
NetSystemRequestBus::BroadcastResult(netContext, &NetSystemRequestBus::Events::GetNetworkContext);
|
||||
AZ_TEST_ASSERT(netContext);
|
||||
|
||||
ComponentType* testComponent = m_entityFrom->FindComponent<ComponentType>();
|
||||
AZ_TEST_ASSERT(testComponent);
|
||||
ReplicaChunkPtr chunk = testComponent->GetNetworkBinding();
|
||||
AZ_TEST_ASSERT(chunk);
|
||||
|
||||
m_outReplica = AZStd::make_unique<GridMate::Replica>("ReplicaTo");
|
||||
{
|
||||
m_outManager = AZStd::make_unique<GridMate::ReplicaManager>();
|
||||
m_outPeer = AZStd::make_unique<GridMate::ReplicaPeer>(m_outManager.get());
|
||||
|
||||
GridMate::WriteBufferDynamic wb(GridMate::EndianType::IgnoreEndian);
|
||||
{
|
||||
GridMate::TimeContext tc;
|
||||
const GridMate::ReplicaContext rc(nullptr, tc);
|
||||
GridMate::MarshalContext mc(GridMate::ReplicaMarshalFlags::FullSync, &wb, nullptr, rc);
|
||||
mc.m_peer = m_outPeer.get();
|
||||
mc.m_rm = m_outManager.get();
|
||||
chunk->Debug_PrepareData(wb.GetEndianType(), GridMate::ReplicaMarshalFlags::FullSync);
|
||||
chunk->Debug_Marshal(mc, 0);
|
||||
}
|
||||
|
||||
// and now unmarshal into the other entity
|
||||
{
|
||||
GridMate::TimeContext tc;
|
||||
const GridMate::ReplicaContext rc(nullptr, tc);
|
||||
GridMate::ReadBuffer rb(wb.GetEndianType(), wb.Get(), wb.Size());
|
||||
GridMate::UnmarshalContext ctx(rc);
|
||||
ctx.m_hasCtorData = false;
|
||||
ctx.m_iBuf = &rb;
|
||||
ctx.m_peer = m_outPeer.get();
|
||||
ctx.m_rm = m_outManager.get();
|
||||
m_outReplicaChunk = chunk->GetDescriptor()->CreateFromStream(ctx);
|
||||
|
||||
m_outReplicaChunk->Debug_AttachedToReplica(m_outReplica.get());
|
||||
ctx.m_peer->Debug_Add(m_outReplica.get());
|
||||
m_outReplicaChunk->Debug_Unmarshal(ctx, 0);
|
||||
/*
|
||||
* Note the order: unmarshal first to populate the chunk with data, then apply it to a component.
|
||||
* The expectation is that the valid will apply to NetBindable::Field without being overwritten.
|
||||
*/
|
||||
m_componentTo->SetNetworkBinding(m_outReplicaChunk);
|
||||
|
||||
// the main test body can now test for the equality
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_outReplicaChunk.reset();
|
||||
m_outManager.reset();
|
||||
m_outPeer.reset();
|
||||
m_outReplica.release(); // Replica is held by as an intrusive pointer in @m_outPeer and is destroyed there.
|
||||
|
||||
if (m_entityFrom)
|
||||
{
|
||||
m_entityFrom->Deactivate();
|
||||
m_entityFrom.reset();
|
||||
}
|
||||
|
||||
if (m_entityTo)
|
||||
{
|
||||
m_entityTo->Deactivate();
|
||||
m_entityTo.reset();
|
||||
}
|
||||
|
||||
m_descTestComponentAutoChunk->ReleaseDescriptor();
|
||||
|
||||
m_app->Stop();
|
||||
m_app.reset();
|
||||
|
||||
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Destroy();
|
||||
AZ::AllocatorInstance<GridMate::GridMateAllocator>::Destroy();
|
||||
|
||||
UnitTest::AllocatorsTestFixture::TearDown();
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AzFramework::Application> m_app;
|
||||
AZStd::unique_ptr<AZ::Entity> m_entityFrom;
|
||||
AZStd::unique_ptr<AZ::Entity> m_entityTo;
|
||||
|
||||
ComponentType* m_componentFrom = nullptr;
|
||||
ComponentType* m_componentTo = nullptr;
|
||||
|
||||
AZ::ComponentDescriptor* m_descTestComponentAutoChunk = nullptr;
|
||||
|
||||
GridMate::ReplicaChunkPtr m_outReplicaChunk;
|
||||
AZStd::unique_ptr<GridMate::Replica> m_outReplica;
|
||||
AZStd::unique_ptr<GridMate::ReplicaManager> m_outManager;
|
||||
AZStd::unique_ptr<GridMate::ReplicaPeer> m_outPeer;
|
||||
};
|
||||
|
||||
using NetContextVector3 = NetContextMarshalFixture<TestComponent_OneField<AZ::Vector3>>;
|
||||
TEST_F(NetContextVector3, SerializationTests)
|
||||
{
|
||||
const Vector3 value = AZ::Vector3::CreateAxisZ( 1.f );
|
||||
|
||||
m_componentFrom->m_field = value;
|
||||
MarshalUnMarshal();
|
||||
|
||||
AZ_TEST_ASSERT(m_componentTo->m_field.Get() == value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now the same test but with NetBindable::BoundField<>
|
||||
*/
|
||||
|
||||
template<typename FieldType>
|
||||
class TestComponent_OneBoundField
|
||||
: public AZ::Component
|
||||
, public NetBindable
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(TestComponent_OneBoundField, "{2B283821-41DF-46BB-BE8E-66EF7301B62A}", AZ::Component, NetBindable);
|
||||
|
||||
using ThisComponentType = TestComponent_OneBoundField<FieldType>;
|
||||
|
||||
static void Reflect(ReflectContext* context)
|
||||
{
|
||||
if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<ThisComponentType, AZ::Component>()
|
||||
->Field("Field", &ThisComponentType::m_boundField)
|
||||
->Version(1);
|
||||
}
|
||||
if (NetworkContext* netContext = azrtti_cast<NetworkContext*>(context))
|
||||
{
|
||||
netContext->Class<ThisComponentType>()
|
||||
->Field("Field", &ThisComponentType::m_boundField);
|
||||
}
|
||||
}
|
||||
|
||||
void Activate() override {}
|
||||
void Deactivate() override {}
|
||||
|
||||
void OnBoundFieldChanged( const FieldType&, const GridMate::TimeContext& ) {}
|
||||
|
||||
BoundField<FieldType, ThisComponentType, &ThisComponentType::OnBoundFieldChanged> m_boundField;
|
||||
};
|
||||
|
||||
using NetContextBoundVector2 = NetContextMarshalFixture<TestComponent_OneBoundField<AZ::Vector2>>;
|
||||
TEST_F(NetContextBoundVector2, SerializationTests)
|
||||
{
|
||||
const Vector2 value = AZ::Vector2::CreateAxisX( 4.f );
|
||||
|
||||
m_componentFrom->m_boundField = value;
|
||||
MarshalUnMarshal();
|
||||
|
||||
AZ_TEST_ASSERT(m_componentTo->m_boundField.Get() == value);
|
||||
}
|
||||
|
||||
TEST_F(NetContextBoundVector2, Delete_Authoritative_Entity)
|
||||
{
|
||||
using ThisComponentType = TestComponent_OneBoundField<AZ::Vector2>;
|
||||
|
||||
AzFramework::NetworkContext* netContext = nullptr;
|
||||
NetSystemRequestBus::BroadcastResult(netContext, &NetSystemRequestBus::Events::GetNetworkContext);
|
||||
AZ_TEST_ASSERT(netContext);
|
||||
ThisComponentType* testComponent = m_entityFrom->FindComponent<ThisComponentType>();
|
||||
AZ_TEST_ASSERT(testComponent);
|
||||
ReplicaChunkPtr chunk = testComponent->GetNetworkBinding();
|
||||
|
||||
// Testing early deletion of an entity on the server.
|
||||
m_entityFrom->Deactivate();
|
||||
m_entityFrom.reset();
|
||||
|
||||
// This test passes if it doesn't crash on cleanup.
|
||||
chunk.reset();
|
||||
}
|
||||
|
||||
template<typename FieldType>
|
||||
class TestComponent_OneBoundField_ServerCallback
|
||||
: public AZ::Component
|
||||
, public NetBindable
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(TestComponent_OneBoundField_ServerCallback, "{74F5B232-0544-45CA-B207-9846052ED1AD}", AZ::Component, NetBindable);
|
||||
|
||||
using ThisComponentType = TestComponent_OneBoundField_ServerCallback<FieldType>;
|
||||
|
||||
static void Reflect(ReflectContext* context)
|
||||
{
|
||||
if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<ThisComponentType, AZ::Component>()
|
||||
->Field("Field", &ThisComponentType::m_boundField)
|
||||
->Version(1);
|
||||
}
|
||||
if (NetworkContext* netContext = azrtti_cast<NetworkContext*>(context))
|
||||
{
|
||||
netContext->Class<ThisComponentType>()
|
||||
->Field("Field", &ThisComponentType::m_boundField);
|
||||
}
|
||||
}
|
||||
|
||||
void Activate() override {}
|
||||
void Deactivate() override {}
|
||||
|
||||
void OnBoundFieldChanged( const FieldType&, const GridMate::TimeContext& )
|
||||
{
|
||||
++m_callbacksInvokeCount;
|
||||
}
|
||||
|
||||
AZ::u8 m_callbacksInvokeCount = 0;
|
||||
|
||||
BoundField<FieldType, ThisComponentType, &ThisComponentType::OnBoundFieldChanged> m_boundField;
|
||||
};
|
||||
|
||||
using NetContextBoundVector2WithCallbackCount = NetContextMarshalFixture<TestComponent_OneBoundField_ServerCallback<AZ::Vector2>>;
|
||||
TEST_F(NetContextBoundVector2WithCallbackCount, BoundField_Invoke_OnServer_Test)
|
||||
{
|
||||
MarshalUnMarshal();
|
||||
|
||||
m_componentFrom->m_callbacksInvokeCount = 0; // resetting the count
|
||||
|
||||
const Vector2 value = AZ::Vector2::CreateAxisX( 4.f );
|
||||
m_componentFrom->m_boundField = value;
|
||||
|
||||
AZ_TEST_ASSERT(m_componentFrom->m_callbacksInvokeCount == 1);
|
||||
}
|
||||
}
|
||||
@@ -1,552 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
#include "TestTypes.h"
|
||||
|
||||
#include <AzCore/Math/Random.h>
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzFramework/Network/EntityIdMarshaler.h>
|
||||
#include <AzFramework/Network/DynamicSerializableFieldMarshaler.h>
|
||||
|
||||
#include <GridMate/Serialize/Buffer.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
template<class T>
|
||||
class MarshalerTester
|
||||
: public AllocatorsFixture
|
||||
{
|
||||
public:
|
||||
MarshalerTester()
|
||||
: m_writeBuffer(GridMate::EndianType::BigEndian)
|
||||
, m_readBuffer(GridMate::EndianType::BigEndian)
|
||||
{
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
AllocatorsFixture::SetUp();
|
||||
m_random.SetSeed(AZStd::chrono::milliseconds().count());
|
||||
}
|
||||
|
||||
void PopulateReadBuffer()
|
||||
{
|
||||
m_readBuffer = GridMate::ReadBuffer(m_writeBuffer.GetEndianType(), m_writeBuffer.Get(), m_writeBuffer.Size());
|
||||
}
|
||||
|
||||
AZ::SimpleLcgRandom m_random;
|
||||
|
||||
GridMate::Marshaler<T> m_marshaler;
|
||||
GridMate::WriteBufferStatic<> m_writeBuffer;
|
||||
GridMate::ReadBuffer m_readBuffer;
|
||||
};
|
||||
|
||||
// EntityIdMarshalerTest
|
||||
typedef MarshalerTester<AZ::EntityId> EntityIdMarshalerTest;
|
||||
|
||||
TEST_F(EntityIdMarshalerTest, SingleMarshalUnmarshalTest_EquivalentEmptyValue)
|
||||
{
|
||||
AZ::EntityId initialId;
|
||||
m_marshaler.Marshal(m_writeBuffer, initialId);
|
||||
|
||||
PopulateReadBuffer();
|
||||
|
||||
AZ::EntityId receivedId;
|
||||
m_marshaler.Unmarshal(receivedId, m_readBuffer);
|
||||
|
||||
EXPECT_EQ(initialId,receivedId);
|
||||
EXPECT_FALSE(receivedId.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(EntityIdMarshalerTest, SingleMarshalUnmarshalTest_EquivalentRandomValue)
|
||||
{
|
||||
AZ::EntityId initialId = AZ::EntityId(m_random.GetRandom());
|
||||
m_marshaler.Marshal(m_writeBuffer, initialId);
|
||||
|
||||
PopulateReadBuffer();
|
||||
|
||||
AZ::EntityId receivedId;
|
||||
m_marshaler.Unmarshal(receivedId, m_readBuffer);
|
||||
|
||||
EXPECT_EQ(initialId,receivedId);
|
||||
}
|
||||
|
||||
TEST_F(EntityIdMarshalerTest, MultipleMarshalUnmarshalTest_EquivalentEmptyRandomEmptyRandomValueChain)
|
||||
{
|
||||
AZ::EntityId sentId1_empty;
|
||||
AZ::EntityId sentId2_random = AZ::EntityId(m_random.GetRandom());
|
||||
AZ::EntityId sentId3_empty;
|
||||
AZ::EntityId sentId4_random = AZ::EntityId(m_random.GetRandom());
|
||||
|
||||
m_marshaler.Marshal(m_writeBuffer, sentId1_empty);
|
||||
m_marshaler.Marshal(m_writeBuffer, sentId2_random);
|
||||
m_marshaler.Marshal(m_writeBuffer, sentId3_empty);
|
||||
m_marshaler.Marshal(m_writeBuffer, sentId4_random);
|
||||
|
||||
PopulateReadBuffer();
|
||||
|
||||
AZ::EntityId receivedId1_empty;
|
||||
AZ::EntityId receivedId2_random;
|
||||
AZ::EntityId receivedId3_empty;
|
||||
AZ::EntityId receivedId4_random;
|
||||
|
||||
m_marshaler.Unmarshal(receivedId1_empty, m_readBuffer);
|
||||
m_marshaler.Unmarshal(receivedId2_random, m_readBuffer);
|
||||
m_marshaler.Unmarshal(receivedId3_empty, m_readBuffer);
|
||||
m_marshaler.Unmarshal(receivedId4_random, m_readBuffer);
|
||||
|
||||
EXPECT_EQ(sentId1_empty, receivedId1_empty);
|
||||
EXPECT_EQ(sentId2_random, receivedId2_random);
|
||||
EXPECT_EQ(sentId3_empty, receivedId3_empty);
|
||||
EXPECT_EQ(sentId4_random, receivedId4_random);
|
||||
}
|
||||
|
||||
// AZ::DynamicSerializableFieldMarshaler
|
||||
class FooSerializable
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(FooSerializable, "{A60F0B2B-6085-4FF1-BD17-A0B0143BB03D}");
|
||||
AZ_CLASS_ALLOCATOR(FooSerializable, AZ::SystemAllocator,0);
|
||||
|
||||
static void Reflect(AZ::SerializeContext& serializeContext)
|
||||
{
|
||||
serializeContext.Class<FooSerializable>()
|
||||
->Version(1)
|
||||
->Field("IntValue", &FooSerializable::m_intValue)
|
||||
->Field("FloatValue", &FooSerializable::m_floatValue)
|
||||
;
|
||||
}
|
||||
|
||||
FooSerializable()
|
||||
: m_intValue(0)
|
||||
, m_floatValue(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const FooSerializable& other) const
|
||||
{
|
||||
return m_intValue == other.m_intValue && AZ::IsClose(m_floatValue, other.m_floatValue,0.0001f);
|
||||
}
|
||||
|
||||
AZ::u32 m_intValue;
|
||||
float m_floatValue;
|
||||
};
|
||||
|
||||
class BarSerializable
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(BarSerializable, "{2389C23F-D247-420B-A385-71AB8455CD2E}");
|
||||
AZ_CLASS_ALLOCATOR(BarSerializable, AZ::SystemAllocator,0);
|
||||
|
||||
static void Reflect(AZ::SerializeContext& serializeContext)
|
||||
{
|
||||
serializeContext.Class<BarSerializable>()
|
||||
->Version(1)
|
||||
->Field("LongValue", &BarSerializable::m_longValue)
|
||||
->Field("DoubleValue", &BarSerializable::m_doubleValue)
|
||||
;
|
||||
}
|
||||
|
||||
BarSerializable()
|
||||
: m_longValue(0)
|
||||
, m_doubleValue(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const BarSerializable& other) const
|
||||
{
|
||||
return m_longValue == other.m_longValue && AZ::IsClose(m_doubleValue,other.m_doubleValue,0.0001);
|
||||
}
|
||||
|
||||
long m_longValue;
|
||||
double m_doubleValue;
|
||||
};
|
||||
|
||||
class ComplexSerializable
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(ComplexSerializable,"{055CB45C-702C-499F-8221-E9ABB21CF1D4}");
|
||||
AZ_CLASS_ALLOCATOR(ComplexSerializable, AZ::SystemAllocator,0);
|
||||
|
||||
static void Reflect(AZ::SerializeContext& serializeContext)
|
||||
{
|
||||
serializeContext.Class<ComplexSerializable>()
|
||||
->Version(1)
|
||||
->Field("FooSerializable",&ComplexSerializable::m_fooField)
|
||||
->Field("BarSerializable",&ComplexSerializable::m_barField)
|
||||
;
|
||||
}
|
||||
|
||||
bool operator==(const ComplexSerializable& other) const
|
||||
{
|
||||
return m_fooField == other.m_fooField && m_barField == other.m_barField;
|
||||
}
|
||||
|
||||
FooSerializable m_fooField;
|
||||
BarSerializable m_barField;
|
||||
};
|
||||
|
||||
class DynamicSerializableFieldMarshalerTest
|
||||
: public MarshalerTester<AZ::DynamicSerializableField>
|
||||
, public AZ::ComponentApplicationBus::Handler
|
||||
{
|
||||
public:
|
||||
DynamicSerializableFieldMarshalerTest()
|
||||
: MarshalerTester<AZ::DynamicSerializableField>()
|
||||
{
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
MarshalerTester<AZ::DynamicSerializableField>::SetUp();
|
||||
|
||||
FooSerializable::Reflect(m_serializeContext);
|
||||
BarSerializable::Reflect(m_serializeContext);
|
||||
ComplexSerializable::Reflect(m_serializeContext);
|
||||
|
||||
// Create the Marshaler with access to our custom serialize context.
|
||||
m_marshaler = GridMate::Marshaler<AZ::DynamicSerializableField>(&m_serializeContext);
|
||||
|
||||
AZ::ComponentApplicationBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
MarshalerTester<AZ::DynamicSerializableField>::TearDown();
|
||||
|
||||
AZ::ComponentApplicationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
FooSerializable* GenerateFooSerializable()
|
||||
{
|
||||
FooSerializable* field = new FooSerializable();
|
||||
|
||||
RandomizeFooSerializable((*field));
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
void RandomizeFooSerializable(FooSerializable& serializable)
|
||||
{
|
||||
serializable.m_intValue = m_random.GetRandom();
|
||||
serializable.m_floatValue = m_random.GetRandomFloat();
|
||||
}
|
||||
|
||||
BarSerializable* GenerateBarSerializable()
|
||||
{
|
||||
BarSerializable* field = new BarSerializable();
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
void RandomizeBarSerializable(BarSerializable& serializable)
|
||||
{
|
||||
serializable.m_longValue = static_cast<long>(m_random.GetRandom());
|
||||
serializable.m_doubleValue = static_cast<double>(m_random.GetRandomFloat());
|
||||
}
|
||||
|
||||
ComplexSerializable* GenerateComplexSerializable()
|
||||
{
|
||||
ComplexSerializable* complexField = new ComplexSerializable();
|
||||
|
||||
RandomizeFooSerializable(complexField->m_fooField);
|
||||
RandomizeBarSerializable(complexField->m_barField);
|
||||
|
||||
return complexField;
|
||||
}
|
||||
|
||||
// Used Component Application Methods
|
||||
AZ::SerializeContext* GetSerializeContext() { return &m_serializeContext; }
|
||||
|
||||
// Unused ComponentApplication methods
|
||||
void RegisterComponentDescriptor(const AZ::ComponentDescriptor* descriptor) override { (void)descriptor; AZ_Assert(false,"Unsupported method in Unit Test"); }
|
||||
void UnregisterComponentDescriptor(const AZ::ComponentDescriptor* descriptor) override { (void)descriptor; AZ_Assert(false,"Unsupported method in Unit Test"); }
|
||||
|
||||
AZ::ComponentApplication* GetApplication() override { AZ_Assert(false,"Unsupported method in Unit Test"); return nullptr; }
|
||||
bool AddEntity(AZ::Entity* entity) override { (void)entity; AZ_Assert(false,"Unsupported method in Unit Test"); return false; }
|
||||
bool RemoveEntity(AZ::Entity* entity) override { (void)entity; AZ_Assert(false,"Unsupported method in Unit Test"); return false; }
|
||||
bool DeleteEntity(const AZ::EntityId& id) override { (void)id; AZ_Assert(false,"Unsupported method in Unit Test"); return false; }
|
||||
AZ::Entity* FindEntity(const AZ::EntityId& id) override { (void)id; AZ_Assert(false,"Unsupported method in Unit Test"); return nullptr; }
|
||||
void EnumerateEntities(const EntityCallback& callback) override { (void)callback; AZ_Assert(false,"Unsupported method in Unit Test"); }
|
||||
AZ::BehaviorContext* GetBehaviorContext() override { AZ_Assert(false,"Unsupported method in Unit Test"); return nullptr; }
|
||||
const char* GetAppRoot() override { AZ_Assert(false,"Unsupported method in Unit Test"); return nullptr; }
|
||||
const char* GetExecutableFolder() override { AZ_Assert(false,"Unsupported method in Unit Test"); return nullptr; }
|
||||
AZ::Debug::DrillerManager* GetDrillerManager() override { AZ_Assert(false,"Unsupported method in Unit Test"); return nullptr; }
|
||||
void ReloadModule(const char* moduleFullPath) override { (void)moduleFullPath; AZ_Assert(false,"Unsupported method in Unit Test"); }
|
||||
|
||||
AZ::SerializeContext m_serializeContext;
|
||||
};
|
||||
|
||||
TEST_F(DynamicSerializableFieldMarshalerTest, SingleMarshalUnmarshalTest_EquivalentEmptyValue)
|
||||
{
|
||||
AZ::DynamicSerializableField sentField;
|
||||
m_marshaler.Marshal(m_writeBuffer, sentField);
|
||||
|
||||
PopulateReadBuffer();
|
||||
|
||||
AZ::DynamicSerializableField receivedField;
|
||||
m_marshaler.Unmarshal(receivedField,m_readBuffer);
|
||||
|
||||
EXPECT_TRUE(sentField.IsEqualTo(receivedField, &m_serializeContext));
|
||||
}
|
||||
|
||||
TEST_F(DynamicSerializableFieldMarshalerTest, SingleMarshalUnmarshalTest_EquivalentFooValue)
|
||||
{
|
||||
AZ::DynamicSerializableField sentField;
|
||||
|
||||
FooSerializable* fooSerializable = GenerateFooSerializable();
|
||||
sentField.Set(fooSerializable);
|
||||
|
||||
m_marshaler.Marshal(m_writeBuffer, sentField);
|
||||
|
||||
PopulateReadBuffer();
|
||||
|
||||
AZ::DynamicSerializableField receivedField;
|
||||
m_marshaler.Unmarshal(receivedField,m_readBuffer);
|
||||
|
||||
EXPECT_TRUE(sentField.IsEqualTo(receivedField, &m_serializeContext));
|
||||
|
||||
sentField.DestroyData(&m_serializeContext);
|
||||
receivedField.DestroyData(&m_serializeContext);
|
||||
}
|
||||
|
||||
TEST_F(DynamicSerializableFieldMarshalerTest, SingleMarshalUnmarshalTest_EquivalentBarValue)
|
||||
{
|
||||
AZ::DynamicSerializableField sentField;
|
||||
|
||||
BarSerializable* barSerializable = GenerateBarSerializable();
|
||||
sentField.Set(barSerializable);
|
||||
|
||||
m_marshaler.Marshal(m_writeBuffer, sentField);
|
||||
|
||||
PopulateReadBuffer();
|
||||
|
||||
AZ::DynamicSerializableField receivedField;
|
||||
m_marshaler.Unmarshal(receivedField,m_readBuffer);
|
||||
|
||||
EXPECT_TRUE(sentField.IsEqualTo(receivedField, &m_serializeContext));
|
||||
|
||||
sentField.DestroyData(&m_serializeContext);
|
||||
receivedField.DestroyData(&m_serializeContext);
|
||||
}
|
||||
|
||||
TEST_F(DynamicSerializableFieldMarshalerTest, SingleMarshalUnmarshalTest_EquivalentComplexValue)
|
||||
{
|
||||
AZ::DynamicSerializableField sentField;
|
||||
|
||||
ComplexSerializable* complexSerializable = GenerateComplexSerializable();
|
||||
sentField.Set(complexSerializable);
|
||||
|
||||
m_marshaler.Marshal(m_writeBuffer, sentField);
|
||||
|
||||
PopulateReadBuffer();
|
||||
|
||||
AZ::DynamicSerializableField receivedField;
|
||||
m_marshaler.Unmarshal(receivedField,m_readBuffer);
|
||||
|
||||
EXPECT_TRUE(sentField.IsEqualTo(receivedField, &m_serializeContext));
|
||||
|
||||
sentField.DestroyData(&m_serializeContext);
|
||||
receivedField.DestroyData(&m_serializeContext);
|
||||
}
|
||||
|
||||
TEST_F(DynamicSerializableFieldMarshalerTest, MultipleMarshalUnmarshalTest_EmptyEmptyChainEquivalentValue)
|
||||
{
|
||||
AZ::DynamicSerializableField sentField1;
|
||||
AZ::DynamicSerializableField sentField2;
|
||||
|
||||
m_marshaler.Marshal(m_writeBuffer, sentField1);
|
||||
m_marshaler.Marshal(m_writeBuffer, sentField2);
|
||||
|
||||
PopulateReadBuffer();
|
||||
|
||||
AZ::DynamicSerializableField receivedField1;
|
||||
AZ::DynamicSerializableField receivedField2;
|
||||
|
||||
m_marshaler.Unmarshal(receivedField1,m_readBuffer);
|
||||
m_marshaler.Unmarshal(receivedField2,m_readBuffer);
|
||||
|
||||
EXPECT_TRUE(sentField1.IsEqualTo(receivedField1, &m_serializeContext));
|
||||
EXPECT_TRUE(sentField2.IsEqualTo(receivedField2, &m_serializeContext));
|
||||
|
||||
sentField1.DestroyData(&m_serializeContext);
|
||||
sentField2.DestroyData(&m_serializeContext);
|
||||
receivedField1.DestroyData(&m_serializeContext);
|
||||
receivedField2.DestroyData(&m_serializeContext);
|
||||
}
|
||||
|
||||
TEST_F(DynamicSerializableFieldMarshalerTest, MultipleMarshalUnmarshalTest_FooBarComplexChainEquivalentValue)
|
||||
{
|
||||
AZ::DynamicSerializableField sentField1;
|
||||
FooSerializable* fooSerializable = GenerateFooSerializable();
|
||||
sentField1.Set(fooSerializable);
|
||||
|
||||
AZ::DynamicSerializableField sentField2;
|
||||
BarSerializable* barSerializable = GenerateBarSerializable();
|
||||
sentField2.Set(barSerializable);
|
||||
|
||||
AZ::DynamicSerializableField sentField3;
|
||||
ComplexSerializable* complexSerializable = GenerateComplexSerializable();
|
||||
sentField3.Set(complexSerializable);
|
||||
|
||||
m_marshaler.Marshal(m_writeBuffer, sentField1);
|
||||
m_marshaler.Marshal(m_writeBuffer, sentField2);
|
||||
m_marshaler.Marshal(m_writeBuffer, sentField3);
|
||||
|
||||
PopulateReadBuffer();
|
||||
|
||||
AZ::DynamicSerializableField receivedField1;
|
||||
AZ::DynamicSerializableField receivedField2;
|
||||
AZ::DynamicSerializableField receivedField3;
|
||||
|
||||
m_marshaler.Unmarshal(receivedField1, m_readBuffer);
|
||||
m_marshaler.Unmarshal(receivedField2, m_readBuffer);
|
||||
m_marshaler.Unmarshal(receivedField3, m_readBuffer);
|
||||
|
||||
EXPECT_TRUE(sentField1.IsEqualTo(receivedField1, &m_serializeContext));
|
||||
EXPECT_TRUE(sentField2.IsEqualTo(receivedField2, &m_serializeContext));
|
||||
EXPECT_TRUE(sentField3.IsEqualTo(receivedField3, &m_serializeContext));
|
||||
|
||||
sentField1.DestroyData(&m_serializeContext);
|
||||
sentField2.DestroyData(&m_serializeContext);
|
||||
sentField3.DestroyData(&m_serializeContext);
|
||||
|
||||
receivedField1.DestroyData(&m_serializeContext);
|
||||
receivedField2.DestroyData(&m_serializeContext);
|
||||
receivedField3.DestroyData(&m_serializeContext);
|
||||
}
|
||||
|
||||
TEST_F(DynamicSerializableFieldMarshalerTest, MultipleMarshalUnmarshalTest_EmptyFooEmptyBarEmptyComplexChainEquivalentValue)
|
||||
{
|
||||
AZ::DynamicSerializableField emptyField;
|
||||
|
||||
AZ::DynamicSerializableField sentField1;
|
||||
FooSerializable* fooSerializable = GenerateFooSerializable();
|
||||
sentField1.Set(fooSerializable);
|
||||
|
||||
AZ::DynamicSerializableField sentField2;
|
||||
BarSerializable* barSerializable = GenerateBarSerializable();
|
||||
sentField2.Set(barSerializable);
|
||||
|
||||
AZ::DynamicSerializableField sentField3;
|
||||
ComplexSerializable* complexSerializable = GenerateComplexSerializable();
|
||||
sentField3.Set(complexSerializable);
|
||||
|
||||
m_marshaler.Marshal(m_writeBuffer, emptyField);
|
||||
m_marshaler.Marshal(m_writeBuffer, sentField1);
|
||||
m_marshaler.Marshal(m_writeBuffer, emptyField);
|
||||
m_marshaler.Marshal(m_writeBuffer, sentField2);
|
||||
m_marshaler.Marshal(m_writeBuffer, emptyField);
|
||||
m_marshaler.Marshal(m_writeBuffer, sentField3);
|
||||
m_marshaler.Marshal(m_writeBuffer, emptyField);
|
||||
|
||||
PopulateReadBuffer();
|
||||
|
||||
AZ::DynamicSerializableField receivedEmptyField1;
|
||||
AZ::DynamicSerializableField receivedField1;
|
||||
AZ::DynamicSerializableField receivedEmptyField2;
|
||||
AZ::DynamicSerializableField receivedField2;
|
||||
AZ::DynamicSerializableField receivedEmptyField3;
|
||||
AZ::DynamicSerializableField receivedField3;
|
||||
AZ::DynamicSerializableField receivedEmptyField4;
|
||||
|
||||
m_marshaler.Unmarshal(receivedEmptyField1, m_readBuffer);
|
||||
m_marshaler.Unmarshal(receivedField1, m_readBuffer);
|
||||
m_marshaler.Unmarshal(receivedEmptyField2, m_readBuffer);
|
||||
m_marshaler.Unmarshal(receivedField2, m_readBuffer);
|
||||
m_marshaler.Unmarshal(receivedEmptyField3, m_readBuffer);
|
||||
m_marshaler.Unmarshal(receivedField3, m_readBuffer);
|
||||
m_marshaler.Unmarshal(receivedEmptyField4, m_readBuffer);
|
||||
|
||||
EXPECT_TRUE(emptyField.IsEqualTo(receivedEmptyField1, &m_serializeContext));
|
||||
EXPECT_TRUE(sentField1.IsEqualTo(receivedField1, &m_serializeContext));
|
||||
EXPECT_TRUE(emptyField.IsEqualTo(receivedEmptyField2, &m_serializeContext));
|
||||
EXPECT_TRUE(sentField2.IsEqualTo(receivedField2, &m_serializeContext));
|
||||
EXPECT_TRUE(emptyField.IsEqualTo(receivedEmptyField3, &m_serializeContext));
|
||||
EXPECT_TRUE(sentField3.IsEqualTo(receivedField3, &m_serializeContext));
|
||||
EXPECT_TRUE(emptyField.IsEqualTo(receivedEmptyField4, &m_serializeContext));
|
||||
|
||||
emptyField.DestroyData(&m_serializeContext);
|
||||
sentField1.DestroyData(&m_serializeContext);
|
||||
sentField2.DestroyData(&m_serializeContext);
|
||||
sentField3.DestroyData(&m_serializeContext);
|
||||
|
||||
receivedEmptyField1.DestroyData(&m_serializeContext);
|
||||
receivedField1.DestroyData(&m_serializeContext);
|
||||
receivedEmptyField2.DestroyData(&m_serializeContext);
|
||||
receivedField2.DestroyData(&m_serializeContext);
|
||||
receivedEmptyField3.DestroyData(&m_serializeContext);
|
||||
receivedField3.DestroyData(&m_serializeContext);
|
||||
receivedEmptyField4.DestroyData(&m_serializeContext);
|
||||
}
|
||||
|
||||
TEST_F(DynamicSerializableFieldMarshalerTest, MultipleMarshalUnmarshalTest_RandomChainEquivalentValue)
|
||||
{
|
||||
// Need to watch out for the size of the WriteBuffer. It's about ~2048 bytes, at worst case here, I'll write ~100 Bytes to the field per test object)
|
||||
// So I need to keep this ~20 elements.
|
||||
int numValues = 5 + m_random.GetRandom()%10;
|
||||
AZStd::vector< AZ::DynamicSerializableField > sentValues;
|
||||
AZStd::vector< AZ::DynamicSerializableField > receivedValues;
|
||||
|
||||
sentValues.resize(numValues);
|
||||
receivedValues.resize(numValues);
|
||||
|
||||
for (auto& currentField : sentValues)
|
||||
{
|
||||
int value = m_random.GetRandom() % 4;
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
currentField.Set(GenerateFooSerializable());
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
currentField.Set(GenerateBarSerializable());
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
currentField.Set(GenerateComplexSerializable());
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
// Empty field
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& currentField : sentValues)
|
||||
{
|
||||
m_marshaler.Marshal(m_writeBuffer,currentField);
|
||||
}
|
||||
|
||||
PopulateReadBuffer();
|
||||
|
||||
for (auto& currentField : receivedValues)
|
||||
{
|
||||
m_marshaler.Unmarshal(currentField,m_readBuffer);
|
||||
}
|
||||
|
||||
for (unsigned int i=0; i < sentValues.size(); ++i)
|
||||
{
|
||||
AZ::DynamicSerializableField& sentField = sentValues[i];
|
||||
AZ::DynamicSerializableField& receivedField = receivedValues[i];
|
||||
|
||||
EXPECT_TRUE(sentField.IsEqualTo(receivedField, &m_serializeContext));
|
||||
|
||||
sentField.DestroyData(&m_serializeContext);
|
||||
receivedField.DestroyData(&m_serializeContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,4 +11,4 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzFrameworkTests_Traits_Android.h>
|
||||
#include <AzFrameworkTests_Traits_Android.h>
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzFrameworkTests_Traits_Linux.h>
|
||||
#include <AzFrameworkTests_Traits_Linux.h>
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzFrameworkTests_Traits_Mac.h>
|
||||
#include <AzFrameworkTests_Traits_Mac.h>
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzFrameworkTests_Traits_Windows.h>
|
||||
#include <AzFrameworkTests_Traits_Windows.h>
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzFrameworkTests_Traits_iOS.h>
|
||||
#include <AzFrameworkTests_Traits_iOS.h>
|
||||
|
||||
+90
-118
@@ -130,6 +130,8 @@ namespace SceneUnitTest
|
||||
m_systemEntity->CreateComponent<AZ::JobManagerComponent>();
|
||||
m_systemEntity->CreateComponent<AZ::StreamerComponent>();
|
||||
m_systemEntity->Activate();
|
||||
|
||||
m_sceneSystem = AzFramework::SceneSystemInterface::Get();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
@@ -146,167 +148,119 @@ namespace SceneUnitTest
|
||||
AZ::IO::FileIOBase* m_prevFileIO;
|
||||
AZ::ComponentApplication m_app;
|
||||
AZ::Entity* m_systemEntity = nullptr;
|
||||
AzFramework::ISceneSystem* m_sceneSystem = nullptr;
|
||||
|
||||
};
|
||||
|
||||
TEST_F(SceneTest, CreateScene)
|
||||
{
|
||||
Scene* scene = nullptr;
|
||||
AZ::Outcome<Scene*, AZStd::string> createSceneOutcome = AZ::Failure<AZStd::string>("");
|
||||
|
||||
{
|
||||
// A scene should be able to be created with a given name.
|
||||
AzFramework::SceneSystemRequestBus::BroadcastResult(createSceneOutcome, &AzFramework::SceneSystemRequestBus::Events::CreateScene, "TestScene");
|
||||
AZ::Outcome<AZStd::shared_ptr<Scene>, AZStd::string> createSceneOutcome = m_sceneSystem->CreateScene("TestScene");
|
||||
EXPECT_TRUE(createSceneOutcome.IsSuccess()) << "Unable to create a scene.";
|
||||
|
||||
// The scene pointer returned should be valid
|
||||
scene = createSceneOutcome.GetValue();
|
||||
EXPECT_TRUE(scene != nullptr) << "Scene creation reported success, but no scene actually was actually returned.";
|
||||
AZStd::shared_ptr<Scene> scene = createSceneOutcome.TakeValue();
|
||||
EXPECT_NE(scene, nullptr) << "Scene creation reported success, but no scene actually was actually returned.";
|
||||
|
||||
// Attempting to create another scene with the same name should fail.
|
||||
createSceneOutcome = AZ::Failure<AZStd::string>("");
|
||||
AzFramework::SceneSystemRequestBus::BroadcastResult(createSceneOutcome, &AzFramework::SceneSystemRequestBus::Events::CreateScene, "TestScene");
|
||||
createSceneOutcome = m_sceneSystem->CreateScene("TestScene");
|
||||
EXPECT_TRUE(!createSceneOutcome.IsSuccess()) << "Should not be able to create two scenes with the same name.";
|
||||
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, GetScene)
|
||||
{
|
||||
Scene* createdScene = nullptr;
|
||||
Scene* retrievedScene = nullptr;
|
||||
Scene* nullScene = nullptr;
|
||||
const static AZStd::string_view s_sceneName = "TestScene";
|
||||
constexpr AZStd::string_view sceneName = "TestScene";
|
||||
|
||||
AZ::Outcome<Scene*, AZStd::string> createSceneOutcome = AZ::Failure<AZStd::string>("");
|
||||
AzFramework::SceneSystemRequestBus::BroadcastResult(createSceneOutcome, &AzFramework::SceneSystemRequestBus::Events::CreateScene, s_sceneName);
|
||||
createdScene = createSceneOutcome.GetValue();
|
||||
AZ::Outcome<AZStd::shared_ptr<Scene>, AZStd::string> createSceneOutcome = m_sceneSystem->CreateScene(sceneName);
|
||||
AZStd::shared_ptr<Scene> createdScene = createSceneOutcome.TakeValue();
|
||||
|
||||
// Should be able to get a scene by name, and it should match the scene that was created.
|
||||
AzFramework::SceneSystemRequestBus::BroadcastResult(retrievedScene, &AzFramework::SceneSystemRequestBus::Events::GetScene, s_sceneName);
|
||||
EXPECT_TRUE(retrievedScene != nullptr) << "Attempting to get scene by name resulted in nullptr.";
|
||||
EXPECT_TRUE(retrievedScene == createdScene) << "Retrieved scene does not match created scene.";
|
||||
AZStd::shared_ptr<Scene> retrievedScene = m_sceneSystem->GetScene(sceneName);
|
||||
EXPECT_NE(retrievedScene, nullptr) << "Attempting to get scene by name resulted in nullptr.";
|
||||
EXPECT_EQ(retrievedScene, createdScene) << "Retrieved scene does not match created scene.";
|
||||
|
||||
// An invalid name should return a null scene.
|
||||
AzFramework::SceneSystemRequestBus::BroadcastResult(nullScene, &AzFramework::SceneSystemRequestBus::Events::GetScene, "non-existant scene");
|
||||
EXPECT_TRUE(nullScene == nullptr) << "Should not be able to retrieve a scene that wasn't created.";
|
||||
AZStd::shared_ptr<Scene> nullScene = m_sceneSystem->GetScene("non-existant scene");
|
||||
EXPECT_EQ(nullScene, nullptr) << "Should not be able to retrieve a scene that wasn't created.";
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, RemoveScene)
|
||||
{
|
||||
Scene* createdScene = nullptr;
|
||||
const static AZStd::string_view s_sceneName = "TestScene";
|
||||
constexpr AZStd::string_view sceneName = "TestScene";
|
||||
|
||||
AZ::Outcome<Scene*, AZStd::string> createSceneOutcome = AZ::Failure<AZStd::string>("");
|
||||
AzFramework::SceneSystemRequestBus::BroadcastResult(createSceneOutcome, &AzFramework::SceneSystemRequestBus::Events::CreateScene, s_sceneName);
|
||||
createdScene = createSceneOutcome.GetValue();
|
||||
|
||||
bool success = false;
|
||||
AzFramework::SceneSystemRequestBus::BroadcastResult(success, &AzFramework::SceneSystemRequestBus::Events::RemoveScene, s_sceneName);
|
||||
AZ::Outcome<AZStd::shared_ptr<Scene>, AZStd::string> createSceneOutcome = m_sceneSystem->CreateScene(sceneName);
|
||||
bool success = m_sceneSystem->RemoveScene(sceneName);
|
||||
EXPECT_TRUE(success) << "Failed to remove the scene that was just created.";
|
||||
|
||||
success = true;
|
||||
AzFramework::SceneSystemRequestBus::BroadcastResult(success, &AzFramework::SceneSystemRequestBus::Events::RemoveScene, "non-existant scene");
|
||||
success = m_sceneSystem->RemoveScene("non-existant scene");
|
||||
EXPECT_FALSE(success) << "Remove scene returned success for a non-existant scene.";
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, GetAllScenes)
|
||||
TEST_F(SceneTest, IterateActiveScenes)
|
||||
{
|
||||
constexpr size_t NumScenes = 5;
|
||||
|
||||
Scene* scenes[NumScenes] = { nullptr };
|
||||
AZStd::shared_ptr<Scene> scenes[NumScenes] = {nullptr};
|
||||
|
||||
for (size_t i = 0; i < NumScenes; ++i)
|
||||
{
|
||||
AZ::Outcome<Scene*, AZStd::string> createSceneOutcome = AZ::Failure<AZStd::string>("");
|
||||
|
||||
AZStd::string sceneName = AZStd::string::format("scene %zu", i);
|
||||
AzFramework::SceneSystemRequestBus::BroadcastResult(createSceneOutcome, &AzFramework::SceneSystemRequestBus::Events::CreateScene, sceneName);
|
||||
scenes[i] = createSceneOutcome.GetValue();
|
||||
AZ::Outcome<AZStd::shared_ptr<Scene>, AZStd::string> createSceneOutcome = m_sceneSystem->CreateScene(sceneName);
|
||||
scenes[i] = createSceneOutcome.TakeValue();
|
||||
}
|
||||
|
||||
AZStd::vector<Scene*> retrievedScenes;
|
||||
AzFramework::SceneSystemRequestBus::BroadcastResult(retrievedScenes, &AzFramework::SceneSystemRequestBus::Events::GetAllScenes);
|
||||
|
||||
EXPECT_EQ(NumScenes, retrievedScenes.size()) << "GetAllScenes() returned a different number of scenes than those created.";
|
||||
|
||||
for (size_t i = 0; i < NumScenes; ++i)
|
||||
{
|
||||
EXPECT_EQ(scenes[i], retrievedScenes.at(i)) << "GetAllScenes() returned scenes in a different order than they were created.";
|
||||
}
|
||||
size_t index = 0;
|
||||
m_sceneSystem->IterateActiveScenes([&index, &scenes](const AZStd::shared_ptr<Scene>& scene)
|
||||
{
|
||||
EXPECT_EQ(scenes[index++], scene);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, EntityContextSceneMapping)
|
||||
TEST_F(SceneTest, IterateZombieScenes)
|
||||
{
|
||||
AZStd::unique_ptr<SliceEntityOwnershipService> m_entityOwnershipService =
|
||||
AZStd::make_unique<AzFramework::SliceEntityOwnershipService>(AZ::Uuid::CreateNull(), m_app.GetSerializeContext());
|
||||
// Create the entity context, entity, and component
|
||||
EntityContext* testEntityContext = new EntityContext(AZ::Uuid::CreateRandom(), AZStd::move(m_entityOwnershipService));
|
||||
testEntityContext->InitContext();
|
||||
EntityContextId testEntityContextId = testEntityContext->GetContextId();
|
||||
AZ::Entity* testEntity = testEntityContext->CreateEntity("TestEntity");
|
||||
TestComponent* testComponent = testEntity->CreateComponent<TestComponent>();
|
||||
constexpr size_t NumScenes = 5;
|
||||
|
||||
// Try to activate an entity and get the scene before a scene has been set. This should fail.
|
||||
TestComponentConfig failConfig;
|
||||
failConfig.m_activateFunction = [](TestComponent* component)
|
||||
AZStd::shared_ptr<Scene> scenes[NumScenes] = {nullptr};
|
||||
|
||||
// Create zombies.
|
||||
for (size_t i = 0; i < NumScenes; ++i)
|
||||
{
|
||||
(void)component;
|
||||
Scene* scene = nullptr;
|
||||
EntityContextId entityContextId = EntityContextId::CreateNull();
|
||||
AZStd::string sceneName = AZStd::string::format("scene %zu", i);
|
||||
AZ::Outcome<AZStd::shared_ptr<Scene>, AZStd::string> createSceneOutcome = m_sceneSystem->CreateScene(sceneName);
|
||||
scenes[i] = createSceneOutcome.TakeValue();
|
||||
m_sceneSystem->RemoveScene(sceneName);
|
||||
}
|
||||
|
||||
AzFramework::EntityIdContextQueryBus::BroadcastResult(entityContextId, &AzFramework::EntityIdContextQueryBus::Events::GetOwningContextId);
|
||||
// Check to make sure there are no more active scenes.
|
||||
size_t index = 0;
|
||||
m_sceneSystem->IterateActiveScenes([&index, &scenes](const AZStd::shared_ptr<Scene>&)
|
||||
{
|
||||
index++;
|
||||
return true;
|
||||
});
|
||||
EXPECT_EQ(0, index);
|
||||
|
||||
// A null scene should be returned since a scene has not been set for this entity context.
|
||||
AzFramework::SceneSystemRequestBus::BroadcastResult(scene, &AzFramework::SceneSystemRequestBus::Events::GetSceneFromEntityContextId, entityContextId);
|
||||
EXPECT_TRUE(scene == nullptr) << "Found a scene when one shouldn't exist.";
|
||||
};
|
||||
|
||||
testComponent->SetConfiguration(failConfig);
|
||||
testComponent->Activate();
|
||||
testComponent->Deactivate();
|
||||
// Check that the scenes are still returned as zombies.
|
||||
index = 0;
|
||||
m_sceneSystem->IterateZombieScenes([&index, &scenes](Scene& scene)
|
||||
{
|
||||
EXPECT_EQ(scenes[index++].get(), &scene);
|
||||
return true;
|
||||
});
|
||||
|
||||
// Create the scene
|
||||
AZ::Outcome<Scene*, AZStd::string> createSceneOutcome = AZ::Failure<AZStd::string>("");
|
||||
AzFramework::SceneSystemRequestBus::BroadcastResult(createSceneOutcome, &AzFramework::SceneSystemRequestBus::Events::CreateScene, "TestScene");
|
||||
Scene* scene = createSceneOutcome.GetValue();
|
||||
|
||||
// Map the Entity context to the scene
|
||||
bool success = false;
|
||||
AzFramework::SceneSystemRequestBus::BroadcastResult(success, &AzFramework::SceneSystemRequestBus::Events::SetSceneForEntityContextId, testEntityContextId, scene);
|
||||
EXPECT_TRUE(success) << "Unable to associate an entity context with a scene.";
|
||||
AzFramework::SceneSystemRequestBus::BroadcastResult(success, &AzFramework::SceneSystemRequestBus::Events::SetSceneForEntityContextId, testEntityContextId, scene);
|
||||
EXPECT_FALSE(success) << "Attempting to map an entity context to a scene that's already mapped, this should not work.";
|
||||
|
||||
// Now it should be possible to get the scene from the entity context within an Entity's Activate()
|
||||
TestComponentConfig successConfig;
|
||||
successConfig.m_activateFunction = [](TestComponent* component)
|
||||
// Check that all scenes are removed when there are no more handles.
|
||||
for (size_t i = 0; i < NumScenes; ++i)
|
||||
{
|
||||
(void)component;
|
||||
Scene* scene = nullptr;
|
||||
EntityContextId entityContextId = EntityContextId::CreateNull();
|
||||
|
||||
AzFramework::EntityIdContextQueryBus::BroadcastResult(entityContextId, &AzFramework::EntityIdContextQueryBus::Events::GetOwningContextId);
|
||||
|
||||
// A scene should be returned since a scene has been set for this entity context.
|
||||
AzFramework::SceneSystemRequestBus::BroadcastResult(scene, &AzFramework::SceneSystemRequestBus::Events::GetSceneFromEntityContextId, entityContextId);
|
||||
EXPECT_TRUE(scene != nullptr) << "Could not find a scene for the entity context.";
|
||||
};
|
||||
|
||||
testComponent->SetConfiguration(successConfig);
|
||||
testComponent->Activate();
|
||||
testComponent->Deactivate();
|
||||
|
||||
// Now remove the entity context / scene association and make sure things fail again.
|
||||
success = false;
|
||||
AzFramework::SceneSystemRequestBus::BroadcastResult(success, &AzFramework::SceneSystemRequestBus::Events::RemoveSceneForEntityContextId, testEntityContextId, nullptr);
|
||||
EXPECT_FALSE(success) << "Should not be able to remove an entity context from a scene it's not associated with.";
|
||||
AzFramework::SceneSystemRequestBus::BroadcastResult(success, &AzFramework::SceneSystemRequestBus::Events::RemoveSceneForEntityContextId, testEntityContextId, scene);
|
||||
EXPECT_TRUE(success) << "Was not able to remove an entity context from a scene it's associated with.";
|
||||
|
||||
testComponent->SetConfiguration(failConfig);
|
||||
testComponent->Activate();
|
||||
testComponent->Deactivate();
|
||||
|
||||
delete testEntityContext; // This should also clean up owned entities / components.
|
||||
scenes[i].reset();
|
||||
}
|
||||
index = 0;
|
||||
m_sceneSystem->IterateZombieScenes([&index, &scenes](Scene&) {
|
||||
index++;
|
||||
return true;
|
||||
});
|
||||
EXPECT_EQ(0, index);
|
||||
}
|
||||
|
||||
// Test classes for use in the SceneSystem test. These can't be defined in the test itself due to some functions created by AZ_RTTI not having a body which breaks VS2015.
|
||||
@@ -324,30 +278,48 @@ namespace SceneUnitTest
|
||||
TEST_F(SceneTest, SceneSystem)
|
||||
{
|
||||
// Create the scene
|
||||
AZ::Outcome<Scene*, AZStd::string> createSceneOutcome = AZ::Failure<AZStd::string>("");
|
||||
AzFramework::SceneSystemRequestBus::BroadcastResult(createSceneOutcome, &AzFramework::SceneSystemRequestBus::Events::CreateScene, "TestScene");
|
||||
AzFramework::Scene* scene = createSceneOutcome.GetValue();
|
||||
AZ::Outcome<AZStd::shared_ptr<Scene>, AZStd::string> createSceneOutcome = m_sceneSystem->CreateScene("TestScene");
|
||||
EXPECT_TRUE(createSceneOutcome.IsSuccess());
|
||||
AZStd::shared_ptr<Scene> scene = createSceneOutcome.TakeValue();
|
||||
|
||||
// Set a class on the Scene
|
||||
Foo1* foo1a = new Foo1();
|
||||
EXPECT_TRUE(scene->SetSubsystem(foo1a));
|
||||
|
||||
// Get that class back from the Scene
|
||||
EXPECT_EQ(foo1a, scene->GetSubsystem<Foo1>());
|
||||
EXPECT_EQ(foo1a, *scene->FindSubsystem<Foo1*>());
|
||||
|
||||
// Try to set the same class type twice, this should fail.
|
||||
Foo1* foo1b = new Foo1();
|
||||
EXPECT_FALSE(scene->SetSubsystem(foo1b));
|
||||
delete foo1b;
|
||||
|
||||
// Add a child scene
|
||||
createSceneOutcome = m_sceneSystem->CreateSceneWithParent("ChildScene", scene);
|
||||
EXPECT_TRUE(createSceneOutcome.IsSuccess());
|
||||
AZStd::shared_ptr<Scene> childScene = createSceneOutcome.TakeValue();
|
||||
|
||||
// Get class back from parent scene.
|
||||
EXPECT_EQ(foo1a, *childScene->FindSubsystem<Foo1*>());
|
||||
|
||||
// Find overloaded version of class on child scene.
|
||||
Foo1* foo1c = new Foo1();
|
||||
EXPECT_TRUE(childScene->SetSubsystem(foo1c));
|
||||
EXPECT_EQ(foo1c, *childScene->FindSubsystem<Foo1*>());
|
||||
|
||||
// Unset system on child scene, using alternative unset function.
|
||||
EXPECT_TRUE(childScene->UnsetSubsystem(foo1c));
|
||||
delete foo1c;
|
||||
|
||||
// Try to un-set a class that was never set, this should fail.
|
||||
EXPECT_FALSE(scene->UnsetSubsystem<Foo2>());
|
||||
|
||||
// Unset the class that was previously set
|
||||
EXPECT_TRUE(scene->UnsetSubsystem<Foo1>());
|
||||
delete foo1a;
|
||||
|
||||
// Make sure that the previsouly set class was really removed.
|
||||
EXPECT_EQ(nullptr, scene->GetSubsystem<Foo1>());
|
||||
// Make sure that the previously set class was really removed.
|
||||
EXPECT_EQ(nullptr, scene->FindSubsystem<Foo1*>());
|
||||
}
|
||||
} // UnitTest
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <AzCore/Script/ScriptContext.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzToolsFramework/ToolsComponents/ScriptEditorComponent.h>
|
||||
#include <AzFramework/Script/ScriptNetBindings.h>
|
||||
|
||||
#include "EntityTestbed.h"
|
||||
|
||||
@@ -63,8 +62,6 @@ namespace UnitTest
|
||||
EBUS_EVENT_RESULT(m_behaviorContext, AZ::ComponentApplicationBus, GetBehaviorContext);
|
||||
EBUS_EVENT_RESULT(m_serializeContext, AZ::ComponentApplicationBus, GetSerializeContext);
|
||||
|
||||
NetBindable::Reflect(m_serializeContext);
|
||||
|
||||
AzToolsFramework::Components::ScriptEditorComponent::CreateDescriptor(); // descriptor is deleted by app
|
||||
AzToolsFramework::Components::ScriptEditorComponent::Reflect(m_serializeContext);
|
||||
|
||||
@@ -228,63 +225,4 @@ namespace UnitTest
|
||||
|
||||
EXPECT_NE(scriptComponent->GetScriptProperty("myNum"), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(ScriptComponentTest, UpdateNetSynchedProperty)
|
||||
{
|
||||
// Make sure altering a netsynched property in script only affects the single entity instance
|
||||
const AZStd::string script = "local test = {\
|
||||
Properties = {\
|
||||
myNetSynchedNum = { default = 41, netSynched ={} },\
|
||||
doUpdate = { default = false },\
|
||||
},\
|
||||
}\
|
||||
function test:OnActivate()\
|
||||
self.tickBusHandler = TickBus.Connect(self, self.entityId)\
|
||||
end\
|
||||
function test:OnDeactivate()\
|
||||
self.tickBusHandler:Disconnect()\
|
||||
end\
|
||||
function test:OnTick(deltaTime, timePoint)\
|
||||
if self.Properties.doUpdate then\
|
||||
self.Properties.myNetSynchedNum = self.Properties.myNetSynchedNum+1\
|
||||
end\
|
||||
end\
|
||||
return test";
|
||||
|
||||
|
||||
const Data::Asset<ScriptAsset> scriptAsset = CreateAndLoadScriptAsset(script);
|
||||
Entity entity1, entity2;
|
||||
ScriptComponent* scriptComponentInstance1 = BuildGameEntity(scriptAsset, entity1);
|
||||
ScriptComponent* scriptComponentInstance2 = BuildGameEntity(scriptAsset, entity2);
|
||||
|
||||
// Change the value of entity1's doUpdate to true.
|
||||
// This way entity1's myNetSynchedNum should be incremented during OnTick
|
||||
auto* doUpdateScriptProperty = azrtti_cast<ScriptPropertyBoolean*>(scriptComponentInstance1->GetScriptProperty("doUpdate"));
|
||||
ASSERT_NE(doUpdateScriptProperty, nullptr);
|
||||
doUpdateScriptProperty->m_value = true;
|
||||
|
||||
entity1.Init();
|
||||
entity2.Init();
|
||||
entity1.Activate();
|
||||
entity2.Activate();
|
||||
|
||||
// Tick in order to call OnTick in our lua script.
|
||||
m_app.Tick();
|
||||
m_app.TickSystem();
|
||||
|
||||
// Ensure Entity1's myNetSynchedNum updated, but not Entity2
|
||||
auto* netSynchedProperty1 = scriptComponentInstance1->GetNetworkedScriptProperty("myNetSynchedNum");
|
||||
auto* netSynchedProperty2 = scriptComponentInstance2->GetNetworkedScriptProperty("myNetSynchedNum");
|
||||
ASSERT_NE(netSynchedProperty1, nullptr);
|
||||
ASSERT_NE(netSynchedProperty2, nullptr);
|
||||
|
||||
auto* num1 = azrtti_cast<const ScriptPropertyNumber*>(netSynchedProperty1);
|
||||
auto* num2 = azrtti_cast<const ScriptPropertyNumber*>(netSynchedProperty2);
|
||||
|
||||
ASSERT_NE(num1, nullptr);
|
||||
ASSERT_NE(num2, nullptr);
|
||||
|
||||
EXPECT_EQ(num1->m_value, 42);
|
||||
EXPECT_EQ(num2->m_value, 41);
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -888,37 +888,6 @@ namespace UnitTest
|
||||
const char* m_objectStreamBuffer = nullptr;
|
||||
};
|
||||
|
||||
class TransformComponentConvertFromV2
|
||||
: public TransformComponentVersionConverter
|
||||
{
|
||||
public:
|
||||
TransformComponentConvertFromV2()
|
||||
{
|
||||
m_objectStreamBuffer =
|
||||
R"DELIMITER(<ObjectStream version="1">
|
||||
<Class name="TransformComponent" field="element" version="2" type="{22B10178-39B6-4C12-BB37-77DB45FDD3B6}">
|
||||
<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
|
||||
<Class name="AZ::u64" field="Id" value="18023671824091307142" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
|
||||
</Class>
|
||||
<Class name="NetBindable" field="BaseClass2" type="{80206665-D429-4703-B42E-94434F82F381}">
|
||||
<Class name="bool" field="m_isSyncEnabled" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
|
||||
</Class>
|
||||
<Class name="EntityId" field="Parent" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
|
||||
<Class name="AZ::u64" field="id" value="4294967295" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
|
||||
</Class>
|
||||
<Class name="Transform" field="Transform" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000" type="{5D9958E9-9F1E-4985-B532-FFFDE75FEDFD}"/>
|
||||
<Class name="Transform" field="LocalTransform" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000" type="{5D9958E9-9F1E-4985-B532-FFFDE75FEDFD}"/>
|
||||
<Class name="unsigned int" field="ParentActivationTransformMode" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
|
||||
</Class>
|
||||
</ObjectStream>)DELIMITER";
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(TransformComponentConvertFromV2, IsStatic_False)
|
||||
{
|
||||
EXPECT_FALSE(m_transformInterface->IsStaticTransform());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// TransformConfig
|
||||
|
||||
|
||||
@@ -12,4 +12,4 @@
|
||||
set(FILES
|
||||
Utils/Utils.h
|
||||
Utils/Utils.cpp
|
||||
)
|
||||
)
|
||||
|
||||
@@ -17,6 +17,8 @@ set(FILES
|
||||
BinToTextEncode.cpp
|
||||
ComponentAddRemove.cpp
|
||||
ComponentAdapterTests.cpp
|
||||
ClickDetectorTests.cpp
|
||||
CursorStateTests.cpp
|
||||
EntityContext.cpp
|
||||
EntityTestbed.h
|
||||
FileFunc.cpp
|
||||
@@ -26,8 +28,6 @@ set(FILES
|
||||
GenAppDescriptors.cpp
|
||||
GenericComponentWrapperTest.cpp
|
||||
InstanceDataHierarchy.cpp
|
||||
NetBinding.cpp
|
||||
NetworkContext.cpp
|
||||
OctreePerformanceTests.cpp
|
||||
OctreeTests.cpp
|
||||
Slices.cpp
|
||||
@@ -35,12 +35,8 @@ set(FILES
|
||||
Script/ScriptEntityTests.cpp
|
||||
AssetCatalog.cpp
|
||||
AssetProcessorConnection.cpp
|
||||
NetBindingSystemImplTest.cpp
|
||||
NetBindingMocks.h
|
||||
NativeWindow.cpp
|
||||
TransformComponent.cpp
|
||||
GridMocks.h
|
||||
InterestManagerComponentTests.cpp
|
||||
SQLiteConnectionTests.cpp
|
||||
ProcessLaunchParseTests.cpp
|
||||
Application.cpp
|
||||
|
||||
Reference in New Issue
Block a user