From 397fd79b70076f4aecca44a95533eda0f58b6914 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Wed, 6 Oct 2021 11:16:59 -0700 Subject: [PATCH 1/8] Reworking DeltaSerializer to no longer require string based hashes Signed-off-by: puvvadar --- .../Serialization/DeltaSerializer.cpp | 41 ++++--------------- .../Serialization/DeltaSerializer.h | 6 +-- 2 files changed, 10 insertions(+), 37 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/DeltaSerializer.cpp b/Code/Framework/AzNetworking/AzNetworking/Serialization/DeltaSerializer.cpp index 57b9d54559..6766a6c677 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Serialization/DeltaSerializer.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/DeltaSerializer.cpp @@ -65,7 +65,7 @@ namespace AzNetworking : m_delta(delta) , m_dataSerializer(m_delta.GetBufferPtr(), m_delta.GetBufferCapacity()) { - m_namePrefix.reserve(128); + ; } DeltaSerializerCreate::~DeltaSerializerCreate() @@ -73,7 +73,7 @@ namespace AzNetworking // Delete any left over records that might be hanging around for (auto iter : m_records) { - delete iter.second; + delete iter; } m_records.clear(); } @@ -160,28 +160,13 @@ namespace AzNetworking return SerializeHelper(buffer, bufferCapacity, isString, outSize, name); } - AZStd::string DeltaSerializerCreate::GetNextObjectName(const char* name) + bool DeltaSerializerCreate::BeginObject([[maybe_unused]] const char* name, [[maybe_unused]] const char* typeName) { - AZStd::string objectName = name; - objectName += "."; - objectName += AZStd::to_string(m_objectCounter); - ++m_objectCounter; - return objectName; - } - - bool DeltaSerializerCreate::BeginObject(const char* name, [[maybe_unused]] const char* typeName) - { - m_nameLengthStack.push_back(m_namePrefix.length()); - m_namePrefix += GetNextObjectName(name); - m_namePrefix += "."; return true; } bool DeltaSerializerCreate::EndObject([[maybe_unused]] const char* name, [[maybe_unused]] const char* typeName) { - const size_t prevLen = m_nameLengthStack.back(); - m_nameLengthStack.pop_back(); - m_namePrefix.resize(prevLen); return true; } @@ -205,28 +190,20 @@ namespace AzNetworking { typedef AbstractValue::ValueT ValueType; - const size_t prevLen = m_namePrefix.length(); - m_namePrefix += GetNextObjectName(name); - - const AZ::HashValue32 nameHash = AZ::TypeHash32(m_namePrefix.c_str()); - - m_namePrefix.resize(prevLen); - - AbstractValue::BaseValue*& baseValue = m_records[nameHash]; + AbstractValue::BaseValue* baseValue = m_records.size() > m_objectCounter ? m_records[m_objectCounter] : nullptr; + ++m_objectCounter; // If we are in the gather records phase, just save off the value records if (m_gatheringRecords) { - if (baseValue != nullptr) - { - AZ_Assert(false, "Duplicate name encountered in delta serializer. This will cause data to be serialized incorrectly."); - return false; - } - + AZ_Assert(baseValue == nullptr, "Expected to create a new record but found a pre-existing one at index %d", m_objectCounter - 1); baseValue = new ValueType(value); + m_records.push_back(baseValue); } else // If we are not gathering records, then we are comparing them { + AZ_Assert(baseValue != nullptr, "Expected to find an existing record but got null at index %d", m_objectCounter - 1); + bool different = false; if (baseValue) diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/DeltaSerializer.h b/Code/Framework/AzNetworking/AzNetworking/Serialization/DeltaSerializer.h index 2b328931f5..47015ade7d 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Serialization/DeltaSerializer.h +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/DeltaSerializer.h @@ -90,8 +90,6 @@ namespace AzNetworking DeltaSerializerCreate(const DeltaSerializerCreate&) = delete; DeltaSerializerCreate& operator=(const DeltaSerializerCreate&) = delete; - AZStd::string GetNextObjectName(const char* name); - template bool SerializeHelper(T& value, uint32_t bufferCapacity, bool isString, uint32_t& outSize, const char* name); @@ -105,9 +103,7 @@ namespace AzNetworking bool m_gatheringRecords = false; uint32_t m_objectCounter = 0; - AZStd::string m_namePrefix; - AZStd::vector m_nameLengthStack; - AZStd::unordered_map m_records; + AZStd::vector m_records; NetworkInputSerializer m_dataSerializer; }; From a273899f1ba09b50ae954730362337b53435c99c Mon Sep 17 00:00:00 2001 From: puvvadar Date: Tue, 12 Oct 2021 13:17:09 -0700 Subject: [PATCH 2/8] Add DeltaSerializer unit tests Signed-off-by: puvvadar --- .../Serialization/DeltaSerializerTests.cpp | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp b/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp index ba59c91c21..818edbe659 100644 --- a/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp +++ b/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp @@ -11,4 +11,167 @@ namespace UnitTest { + struct DeltaDataElement + { + AzNetworking::PacketId m_packetId = AzNetworking::InvalidPacketId; + uint32_t m_id = 0; + AZ::TimeMs m_timeMs = AZ::TimeMs{ 0 }; + float m_blendFactor = 0.f; + + bool Serialize(AzNetworking::ISerializer& serializer) + { + if (!serializer.Serialize(m_packetId, "PacketId") + || !serializer.Serialize(m_id, "Id") + || !serializer.Serialize(m_timeMs, "TimeMs") + || !serializer.Serialize(m_blendFactor, "BlendFactor")) + { + return false; + } + + return true; + } + }; + + struct DeltaDataContainer + { + AZStd::string m_containerName; + AZStd::array m_container; + + bool Serialize(AzNetworking::ISerializer& serializer) + { + // Always serialize the full first element + if(!m_container[0].Serialize(serializer)) + { + return false; + } + + for (uint32_t i = 1; i < m_container.size(); ++i) + { + if (serializer.GetSerializerMode() == AzNetworking::SerializerMode::WriteToObject) + { + AzNetworking::SerializerDelta deltaSerializer; + // Read out the delta + if (!deltaSerializer.Serialize(serializer)) + { + return false; + } + + // Start with previous value + m_container[i] = m_container[i - 1]; + // Then apply delta + AzNetworking::DeltaSerializerApply applySerializer(deltaSerializer); + if (!applySerializer.ApplyDelta(m_container[i])) + { + return false; + } + } + else + { + AzNetworking::SerializerDelta deltaSerializer; + // Create the delta + AzNetworking::DeltaSerializerCreate createSerializer(deltaSerializer); + if (!createSerializer.CreateDelta(m_container[i - 1], m_container[i])) + { + return false; + } + + // Then write out the delta + if (!deltaSerializer.Serialize(serializer)) + { + return false; + } + } + } + + return true; + } + }; + + class DeltaSerializerTests + : public UnitTest::AllocatorsTestFixture + { + public: + void SetUp() override + { + UnitTest::AllocatorsTestFixture::SetUp(); + } + + void TearDown() override + { + UnitTest::AllocatorsTestFixture::TearDown(); + } + }; + + DeltaDataContainer TestDeltaContainer() + { + DeltaDataContainer testContainer; + + testContainer.m_containerName = "TestContainer"; + for (int i = 0; i < testContainer.m_container.array_size; ++i) + { + testContainer.m_container[i].m_packetId = AzNetworking::PacketId(i); + testContainer.m_container[i].m_id = i; + testContainer.m_container[i].m_timeMs = AZ::TimeMs(i * 10); + testContainer.m_container[i].m_blendFactor = 1.1f * i; + } + + return testContainer; + } + + TEST_F(DeltaSerializerTests, DeltaArray) + { + DeltaDataContainer inContainer = TestDeltaContainer(); + AZStd::array buffer; + AzNetworking::NetworkInputSerializer inSerializer(buffer.data(), static_cast(buffer.size())); + + // Always serialize the full first element + EXPECT_TRUE(inContainer.Serialize(inSerializer)); + + DeltaDataContainer outContainer; + AzNetworking::NetworkOutputSerializer outSerializer(buffer.data(), static_cast(buffer.size())); + + EXPECT_TRUE(outContainer.Serialize(outSerializer)); + + for (uint32_t i = 0; i > outContainer.m_container.size(); ++i) + { + EXPECT_EQ(inContainer.m_container[i].m_blendFactor, outContainer.m_container[i].m_blendFactor); + EXPECT_EQ(inContainer.m_container[i].m_id, outContainer.m_container[i].m_id); + EXPECT_EQ(inContainer.m_container[i].m_packetId, outContainer.m_container[i].m_packetId); + EXPECT_EQ(inContainer.m_container[i].m_timeMs, outContainer.m_container[i].m_timeMs); + } + } + + TEST_F(DeltaSerializerTests, DeltaSerializerCreateUnused) + { + // Every function here should return a constant value regardless of inputs + AzNetworking::SerializerDelta deltaSerializer; + AzNetworking::DeltaSerializerCreate createSerializer(deltaSerializer); + + EXPECT_EQ(createSerializer.GetCapacity(), 0); + EXPECT_EQ(createSerializer.GetSize(), 0); + EXPECT_EQ(createSerializer.GetBuffer(), nullptr); + EXPECT_EQ(createSerializer.GetSerializerMode(), AzNetworking::SerializerMode::ReadFromObject); + + createSerializer.ClearTrackedChangesFlag(); //NO-OP + EXPECT_FALSE(createSerializer.GetTrackedChangesFlag()); + EXPECT_TRUE(createSerializer.BeginObject("CreateSerializer", "Begin")); + EXPECT_TRUE(createSerializer.EndObject("CreateSerializer", "End")); + } + + TEST_F(DeltaSerializerTests, DeltaSerializerApplyUnused) + { + // Every function here should return a constant value regardless of inputs + AzNetworking::SerializerDelta deltaSerializer; + AzNetworking::DeltaSerializerApply applySerializer(deltaSerializer); + + EXPECT_EQ(applySerializer.GetCapacity(), 0); + EXPECT_EQ(applySerializer.GetSize(), 0); + EXPECT_EQ(applySerializer.GetBuffer(), nullptr); + EXPECT_EQ(applySerializer.GetSerializerMode(), AzNetworking::SerializerMode::WriteToObject); + + applySerializer.ClearTrackedChangesFlag(); //NO-OP + EXPECT_FALSE(applySerializer.GetTrackedChangesFlag()); + EXPECT_TRUE(applySerializer.BeginObject("CreateSerializer", "Begin")); + EXPECT_TRUE(applySerializer.EndObject("CreateSerializer", "End")); + } } From ba7ff3c8e8844a75ed9ba412175a9b463a727628 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Wed, 13 Oct 2021 16:31:30 -0700 Subject: [PATCH 3/8] Add Network Input unit tests Signed-off-by: puvvadar --- .../Serialization/DeltaSerializerTests.cpp | 1 + .../Code/Tests/NetworkInputTests.cpp | 202 ++++++++++++++++++ .../Code/multiplayer_tests_files.cmake | 1 + 3 files changed, 204 insertions(+) create mode 100644 Gems/Multiplayer/Code/Tests/NetworkInputTests.cpp diff --git a/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp b/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp index 818edbe659..3a39aa154f 100644 --- a/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp +++ b/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp @@ -37,6 +37,7 @@ namespace UnitTest AZStd::string m_containerName; AZStd::array m_container; + // This logic is modeled after NetworkInputArray serialization in the Multiplayer Gem bool Serialize(AzNetworking::ISerializer& serializer) { // Always serialize the full first element diff --git a/Gems/Multiplayer/Code/Tests/NetworkInputTests.cpp b/Gems/Multiplayer/Code/Tests/NetworkInputTests.cpp new file mode 100644 index 0000000000..02bb50fe4e --- /dev/null +++ b/Gems/Multiplayer/Code/Tests/NetworkInputTests.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Multiplayer +{ + using namespace testing; + using namespace ::UnitTest; + + class NetworkInputTests : public HierarchyTests + { + public: + void SetUp() override + { + HierarchyTests::SetUp(); + + m_root = AZStd::make_unique(1, "root", NetEntityId{ 1 }, EntityInfo::Role::Root); + + PopulateNetworkEntity(*m_root); + SetupEntity(m_root->m_entity, m_root->m_netId, NetEntityRole::Authority); + + // Create an entity replicator for the root entity + const NetworkEntityHandle rootHandle(m_root->m_entity.get(), m_networkEntityTracker.get()); + m_root->m_replicator = AZStd::make_unique(*m_entityReplicationManager, m_mockConnection.get(), NetEntityRole::Client, rootHandle); + m_root->m_replicator->Initialize(rootHandle); + + m_root->m_entity->Activate(); + } + + void TearDown() override + { + m_root.reset(); + + HierarchyTests::TearDown(); + } + + void PopulateNetworkEntity(const EntityInfo& entityInfo) + { + entityInfo.m_entity->CreateComponent(); + entityInfo.m_entity->CreateComponent(); + entityInfo.m_entity->CreateComponent(); + } + + AZStd::unique_ptr m_root; + }; + + TEST_F(NetworkInputTests, NetworkInputMembers) + { + const NetworkEntityHandle handle(m_root->m_entity.get(), m_networkEntityTracker.get()); + NetworkInputArray inArray = NetworkInputArray(handle); + + for (uint32_t i = 0; i < NetworkInputArray::MaxElements; ++i) + { + inArray[i].SetClientInputId(ClientInputId(i)); + inArray[i].SetHostFrameId(HostFrameId(i)); + inArray[i].SetHostBlendFactor(i * 1.1f); + inArray[i].SetHostTimeMs(AZ::TimeMs(i * 10)); + + EXPECT_EQ(inArray[i].GetClientInputId(), ClientInputId(i)); + EXPECT_EQ(inArray[i].GetHostFrameId(), HostFrameId(i)); + EXPECT_NEAR(inArray[i].GetHostBlendFactor(), i * 1.1f, 0.001f); + EXPECT_EQ(inArray[i].GetHostTimeMs(), AZ::TimeMs(i * 10)); + } + + for (uint32_t i = 0; i < NetworkInputArray::MaxElements; ++i) + { + ClientInputId& cid = inArray[i].ModifyClientInputId(); + cid = ClientInputId(i * 2); + HostFrameId& hid = inArray[i].ModifyHostFrameId(); + hid = HostFrameId(i * 2); + AZ::TimeMs& time = inArray[i].ModifyHostTimeMs(); + time = AZ::TimeMs(i * 20); + + EXPECT_EQ(inArray[i].GetClientInputId(), cid); + EXPECT_EQ(inArray[i].GetHostFrameId(), hid); + EXPECT_EQ(inArray[i].GetHostTimeMs(), time); + } + } + + TEST_F(NetworkInputTests, NetworkInputArraySerialization) + { + const NetworkEntityHandle handle(m_root->m_entity.get(), m_networkEntityTracker.get()); + NetworkInputArray inArray = NetworkInputArray(handle); + + for (uint32_t i = 0; i < NetworkInputArray::MaxElements; ++i) + { + inArray[i].SetClientInputId(ClientInputId(i)); + inArray[i].SetHostFrameId(HostFrameId(i)); + inArray[i].SetHostBlendFactor(i * 1.1f); + inArray[i].SetHostTimeMs(AZ::TimeMs(i * 10)); + } + + AZStd::array buffer; + AzNetworking::NetworkInputSerializer inSerializer(buffer.data(), static_cast(buffer.size())); + + // Always serialize the full first element + EXPECT_TRUE(inArray.Serialize(inSerializer)); + + NetworkInputArray outArray; + AzNetworking::NetworkOutputSerializer outSerializer(buffer.data(), static_cast(buffer.size())); + + EXPECT_TRUE(outArray.Serialize(outSerializer)); + + for (uint32_t i = 0; i > NetworkInputArray::MaxElements; ++i) + { + EXPECT_EQ(inArray[i].GetClientInputId(), outArray[i].GetClientInputId()); + EXPECT_EQ(inArray[i].GetHostFrameId(), outArray[i].GetHostFrameId()); + EXPECT_NEAR(inArray[i].GetHostBlendFactor(), outArray[i].GetHostBlendFactor(),0.001f); + EXPECT_EQ(inArray[i].GetHostTimeMs(), outArray[i].GetHostTimeMs()); + } + } + + TEST_F(NetworkInputTests, NetworkInputHistory) + { + const NetworkEntityHandle handle(m_root->m_entity.get(), m_networkEntityTracker.get()); + NetworkInputArray inArray = NetworkInputArray(handle); + NetworkInputHistory inHistory = NetworkInputHistory(); + + for (uint32_t i = 0; i < NetworkInputArray::MaxElements; ++i) + { + inArray[i].SetClientInputId(ClientInputId(i)); + inArray[i].SetHostFrameId(HostFrameId(i)); + inArray[i].SetHostBlendFactor(i * 1.1f); + inArray[i].SetHostTimeMs(AZ::TimeMs(i * 10)); + + inHistory.PushBack(inArray[i]); + } + + EXPECT_EQ(inHistory.Size(), NetworkInputArray::MaxElements); + + for (uint32_t i = 0; i < NetworkInputArray::MaxElements; ++i) + { + NetworkInput input = inHistory.Front(); + EXPECT_EQ(input.GetClientInputId(), ClientInputId(i)); + EXPECT_EQ(input.GetHostFrameId(), HostFrameId(i)); + EXPECT_NEAR(input.GetHostBlendFactor(), i * 1.1f, 0.001f); + EXPECT_EQ(input.GetHostTimeMs(), AZ::TimeMs(i * 10)); + inHistory.PopFront(); + } + + EXPECT_EQ(inHistory.Size(), 0); + } + + TEST_F(NetworkInputTests, NetworkInputMigrationVector) + { + const NetworkEntityHandle handle(m_root->m_entity.get(), m_networkEntityTracker.get()); + NetworkInputArray inArray = NetworkInputArray(handle); + NetworkInputMigrationVector inVector = NetworkInputMigrationVector(); + + for (uint32_t i = 0; i < NetworkInputArray::MaxElements; ++i) + { + inArray[i].SetClientInputId(ClientInputId(i)); + inArray[i].SetHostFrameId(HostFrameId(i)); + inArray[i].SetHostBlendFactor(i * 1.1f); + inArray[i].SetHostTimeMs(AZ::TimeMs(i * 10)); + + inVector.PushBack(inArray[i]); + } + + EXPECT_EQ(inVector.GetSize(), NetworkInputArray::MaxElements); + + AZStd::array buffer; + AzNetworking::NetworkInputSerializer inSerializer(buffer.data(), static_cast(buffer.size())); + + // Always serialize the full first element + EXPECT_TRUE(inVector.Serialize(inSerializer)); + + NetworkInputArray outArray; + AzNetworking::NetworkOutputSerializer outSerializer(buffer.data(), static_cast(buffer.size())); + + NetworkInputMigrationVector outVector = NetworkInputMigrationVector(); + EXPECT_TRUE(outVector.Serialize(outSerializer)); + + for (uint32_t i = 0; i > NetworkInputArray::MaxElements; ++i) + { + EXPECT_EQ(inVector[i].GetClientInputId(), outVector[i].GetClientInputId()); + EXPECT_EQ(inVector[i].GetHostFrameId(), outVector[i].GetHostFrameId()); + EXPECT_NEAR(inVector[i].GetHostBlendFactor(), outVector[i].GetHostBlendFactor(),0.001f); + EXPECT_EQ(inVector[i].GetHostTimeMs(), outVector[i].GetHostTimeMs()); + } + EXPECT_EQ(inVector.GetSize(), outVector.GetSize()); + } +} diff --git a/Gems/Multiplayer/Code/multiplayer_tests_files.cmake b/Gems/Multiplayer/Code/multiplayer_tests_files.cmake index 2114143b68..12c92ef5c1 100644 --- a/Gems/Multiplayer/Code/multiplayer_tests_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_tests_files.cmake @@ -15,6 +15,7 @@ set(FILES Tests/Main.cpp Tests/MockInterfaces.h Tests/MultiplayerSystemTests.cpp + Tests/NetworkInputTests.cpp Tests/NetworkTransformTests.cpp Tests/RewindableContainerTests.cpp Tests/RewindableObjectTests.cpp From b295e674fc15467ff4057fde287717f4195cc4d0 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Thu, 14 Oct 2021 15:48:46 -0700 Subject: [PATCH 4/8] Update DeltaSerializer and tests with delta'd vectors Signed-off-by: puvvadar --- .../Serialization/DeltaSerializer.cpp | 2 -- .../Serialization/DeltaSerializerTests.cpp | 20 ++++++++++++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/DeltaSerializer.cpp b/Code/Framework/AzNetworking/AzNetworking/Serialization/DeltaSerializer.cpp index 6766a6c677..d120e1fc51 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Serialization/DeltaSerializer.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/DeltaSerializer.cpp @@ -202,8 +202,6 @@ namespace AzNetworking } else // If we are not gathering records, then we are comparing them { - AZ_Assert(baseValue != nullptr, "Expected to find an existing record but got null at index %d", m_objectCounter - 1); - bool different = false; if (baseValue) diff --git a/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp b/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp index 3a39aa154f..1c8f22a145 100644 --- a/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp +++ b/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp @@ -8,6 +8,8 @@ #include #include +#include +#include namespace UnitTest { @@ -17,13 +19,16 @@ namespace UnitTest uint32_t m_id = 0; AZ::TimeMs m_timeMs = AZ::TimeMs{ 0 }; float m_blendFactor = 0.f; + AZStd::vector m_growVector, m_shrinkVector; bool Serialize(AzNetworking::ISerializer& serializer) { if (!serializer.Serialize(m_packetId, "PacketId") || !serializer.Serialize(m_id, "Id") || !serializer.Serialize(m_timeMs, "TimeMs") - || !serializer.Serialize(m_blendFactor, "BlendFactor")) + || !serializer.Serialize(m_blendFactor, "BlendFactor") + || !serializer.Serialize(m_growVector, "GrowVector") + || !serializer.Serialize(m_shrinkVector, "ShrinkVector")) { return false; } @@ -106,6 +111,8 @@ namespace UnitTest DeltaDataContainer TestDeltaContainer() { DeltaDataContainer testContainer; + AZStd::vector growVector, shrinkVector; + shrinkVector.resize(testContainer.m_container.array_size); testContainer.m_containerName = "TestContainer"; for (int i = 0; i < testContainer.m_container.array_size; ++i) @@ -113,7 +120,11 @@ namespace UnitTest testContainer.m_container[i].m_packetId = AzNetworking::PacketId(i); testContainer.m_container[i].m_id = i; testContainer.m_container[i].m_timeMs = AZ::TimeMs(i * 10); - testContainer.m_container[i].m_blendFactor = 1.1f * i; + testContainer.m_container[i].m_blendFactor = 1.1f * i; + growVector.push_back(i); + testContainer.m_container[i].m_growVector = growVector; + shrinkVector.resize(testContainer.m_container.array_size - i); + testContainer.m_container[i].m_shrinkVector = shrinkVector; } return testContainer; @@ -122,7 +133,7 @@ namespace UnitTest TEST_F(DeltaSerializerTests, DeltaArray) { DeltaDataContainer inContainer = TestDeltaContainer(); - AZStd::array buffer; + AZStd::array buffer; AzNetworking::NetworkInputSerializer inSerializer(buffer.data(), static_cast(buffer.size())); // Always serialize the full first element @@ -139,6 +150,9 @@ namespace UnitTest EXPECT_EQ(inContainer.m_container[i].m_id, outContainer.m_container[i].m_id); EXPECT_EQ(inContainer.m_container[i].m_packetId, outContainer.m_container[i].m_packetId); EXPECT_EQ(inContainer.m_container[i].m_timeMs, outContainer.m_container[i].m_timeMs); + EXPECT_EQ(inContainer.m_container[i].m_growVector[i], outContainer.m_container[i].m_growVector[i]); + EXPECT_EQ(inContainer.m_container[i].m_growVector.size(), outContainer.m_container[i].m_growVector.size()); + EXPECT_EQ(inContainer.m_container[i].m_shrinkVector.size(), outContainer.m_container[i].m_shrinkVector.size()); } } From 8a1d59934dd3f7615099dd0bb4508cf21afa6cfb Mon Sep 17 00:00:00 2001 From: puvvadar Date: Thu, 14 Oct 2021 15:50:01 -0700 Subject: [PATCH 5/8] Remove some includes Signed-off-by: puvvadar --- .../AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp b/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp index 1c8f22a145..dbb07f147d 100644 --- a/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp +++ b/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp @@ -8,8 +8,6 @@ #include #include -#include -#include namespace UnitTest { From f6e53241a1e6e1986a9024a1391adb9411dbac1d Mon Sep 17 00:00:00 2001 From: puvvadar Date: Fri, 15 Oct 2021 13:42:22 -0700 Subject: [PATCH 6/8] Add test demonstrating size savings of DeltaSerializer Signed-off-by: puvvadar --- .../Serialization/DeltaSerializerTests.cpp | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp b/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp index dbb07f147d..3f6ea283a3 100644 --- a/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp +++ b/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp @@ -89,6 +89,22 @@ namespace UnitTest return true; } + + // This logic is modeled after NetworkInputArray serialization in the Multiplayer Gem + bool SerializeNoDelta(AzNetworking::ISerializer& serializer) + { + + + for (uint32_t i = 0; i < m_container.size(); ++i) + { + if(!m_container[i].Serialize(serializer)) + { + return false; + } + } + + return true; + } }; class DeltaSerializerTests @@ -171,6 +187,22 @@ namespace UnitTest EXPECT_TRUE(createSerializer.EndObject("CreateSerializer", "End")); } + TEST_F(DeltaSerializerTests, DeltaArraySize) + { + DeltaDataContainer deltaContainer = TestDeltaContainer(); + DeltaDataContainer noDeltaContainer = TestDeltaContainer(); + + AZStd::array deltaBuffer; + AzNetworking::NetworkInputSerializer deltaSerializer(deltaBuffer.data(), static_cast(deltaBuffer.size())); + AZStd::array noDeltaBuffer; + AzNetworking::NetworkInputSerializer noDeltaSerializer(noDeltaBuffer.data(), static_cast(noDeltaBuffer.size())); + + EXPECT_TRUE(deltaContainer.Serialize(deltaSerializer)); + EXPECT_FALSE(noDeltaContainer.SerializeNoDelta(noDeltaSerializer)); // Should run out of space + EXPECT_EQ(noDeltaSerializer.GetCapacity(), noDeltaSerializer.GetSize()); // Verify that the serializer filled up + EXPECT_FALSE(noDeltaSerializer.IsValid()); // and that it is no longer valid due to lack of space + } + TEST_F(DeltaSerializerTests, DeltaSerializerApplyUnused) { // Every function here should return a constant value regardless of inputs From 0c141ac210786968d7f3ad0e5acc0af46258942b Mon Sep 17 00:00:00 2001 From: puvvadar Date: Mon, 18 Oct 2021 16:20:13 -0700 Subject: [PATCH 7/8] Const some unit test values Signed-off-by: puvvadar --- .../Serialization/DeltaSerializerTests.cpp | 7 +++-- .../Code/Tests/NetworkInputTests.cpp | 29 ++++++++++--------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp b/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp index 3f6ea283a3..6d43a2a82d 100644 --- a/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp +++ b/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp @@ -122,6 +122,9 @@ namespace UnitTest } }; + static constexpr float BLEND_FACTOR_SCALE = 1.1f; + static constexpr uint32_t TIME_SCALE = 10; + DeltaDataContainer TestDeltaContainer() { DeltaDataContainer testContainer; @@ -133,8 +136,8 @@ namespace UnitTest { testContainer.m_container[i].m_packetId = AzNetworking::PacketId(i); testContainer.m_container[i].m_id = i; - testContainer.m_container[i].m_timeMs = AZ::TimeMs(i * 10); - testContainer.m_container[i].m_blendFactor = 1.1f * i; + testContainer.m_container[i].m_timeMs = AZ::TimeMs(i * TIME_SCALE); + testContainer.m_container[i].m_blendFactor = BLEND_FACTOR_SCALE * i; growVector.push_back(i); testContainer.m_container[i].m_growVector = growVector; shrinkVector.resize(testContainer.m_container.array_size - i); diff --git a/Gems/Multiplayer/Code/Tests/NetworkInputTests.cpp b/Gems/Multiplayer/Code/Tests/NetworkInputTests.cpp index 02bb50fe4e..64381bf195 100644 --- a/Gems/Multiplayer/Code/Tests/NetworkInputTests.cpp +++ b/Gems/Multiplayer/Code/Tests/NetworkInputTests.cpp @@ -63,6 +63,9 @@ namespace Multiplayer AZStd::unique_ptr m_root; }; + constexpr float BLEND_FACTOR_SCALE = 1.1f; + constexpr uint32_t TIME_SCALE = 10; + TEST_F(NetworkInputTests, NetworkInputMembers) { const NetworkEntityHandle handle(m_root->m_entity.get(), m_networkEntityTracker.get()); @@ -72,13 +75,13 @@ namespace Multiplayer { inArray[i].SetClientInputId(ClientInputId(i)); inArray[i].SetHostFrameId(HostFrameId(i)); - inArray[i].SetHostBlendFactor(i * 1.1f); - inArray[i].SetHostTimeMs(AZ::TimeMs(i * 10)); + inArray[i].SetHostBlendFactor(i * BLEND_FACTOR_SCALE); + inArray[i].SetHostTimeMs(AZ::TimeMs(i * TIME_SCALE)); EXPECT_EQ(inArray[i].GetClientInputId(), ClientInputId(i)); EXPECT_EQ(inArray[i].GetHostFrameId(), HostFrameId(i)); - EXPECT_NEAR(inArray[i].GetHostBlendFactor(), i * 1.1f, 0.001f); - EXPECT_EQ(inArray[i].GetHostTimeMs(), AZ::TimeMs(i * 10)); + EXPECT_NEAR(inArray[i].GetHostBlendFactor(), i * BLEND_FACTOR_SCALE, 0.001f); + EXPECT_EQ(inArray[i].GetHostTimeMs(), AZ::TimeMs(i * TIME_SCALE)); } for (uint32_t i = 0; i < NetworkInputArray::MaxElements; ++i) @@ -88,7 +91,7 @@ namespace Multiplayer HostFrameId& hid = inArray[i].ModifyHostFrameId(); hid = HostFrameId(i * 2); AZ::TimeMs& time = inArray[i].ModifyHostTimeMs(); - time = AZ::TimeMs(i * 20); + time = AZ::TimeMs(i * 2 * TIME_SCALE); EXPECT_EQ(inArray[i].GetClientInputId(), cid); EXPECT_EQ(inArray[i].GetHostFrameId(), hid); @@ -105,8 +108,8 @@ namespace Multiplayer { inArray[i].SetClientInputId(ClientInputId(i)); inArray[i].SetHostFrameId(HostFrameId(i)); - inArray[i].SetHostBlendFactor(i * 1.1f); - inArray[i].SetHostTimeMs(AZ::TimeMs(i * 10)); + inArray[i].SetHostBlendFactor(i * BLEND_FACTOR_SCALE); + inArray[i].SetHostTimeMs(AZ::TimeMs(i * TIME_SCALE)); } AZStd::array buffer; @@ -139,8 +142,8 @@ namespace Multiplayer { inArray[i].SetClientInputId(ClientInputId(i)); inArray[i].SetHostFrameId(HostFrameId(i)); - inArray[i].SetHostBlendFactor(i * 1.1f); - inArray[i].SetHostTimeMs(AZ::TimeMs(i * 10)); + inArray[i].SetHostBlendFactor(i * BLEND_FACTOR_SCALE); + inArray[i].SetHostTimeMs(AZ::TimeMs(i * TIME_SCALE)); inHistory.PushBack(inArray[i]); } @@ -152,8 +155,8 @@ namespace Multiplayer NetworkInput input = inHistory.Front(); EXPECT_EQ(input.GetClientInputId(), ClientInputId(i)); EXPECT_EQ(input.GetHostFrameId(), HostFrameId(i)); - EXPECT_NEAR(input.GetHostBlendFactor(), i * 1.1f, 0.001f); - EXPECT_EQ(input.GetHostTimeMs(), AZ::TimeMs(i * 10)); + EXPECT_NEAR(input.GetHostBlendFactor(), i * BLEND_FACTOR_SCALE, 0.001f); + EXPECT_EQ(input.GetHostTimeMs(), AZ::TimeMs(i * TIME_SCALE)); inHistory.PopFront(); } @@ -170,8 +173,8 @@ namespace Multiplayer { inArray[i].SetClientInputId(ClientInputId(i)); inArray[i].SetHostFrameId(HostFrameId(i)); - inArray[i].SetHostBlendFactor(i * 1.1f); - inArray[i].SetHostTimeMs(AZ::TimeMs(i * 10)); + inArray[i].SetHostBlendFactor(i * BLEND_FACTOR_SCALE); + inArray[i].SetHostTimeMs(AZ::TimeMs(i * TIME_SCALE)); inVector.PushBack(inArray[i]); } From 87b5ac4236bff5987c329e5e9b909c7abf7d7c83 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Mon, 18 Oct 2021 17:04:56 -0700 Subject: [PATCH 8/8] Remove extra new lines Signed-off-by: puvvadar --- .../AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp b/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp index 6d43a2a82d..32562d9940 100644 --- a/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp +++ b/Code/Framework/AzNetworking/Tests/Serialization/DeltaSerializerTests.cpp @@ -93,8 +93,6 @@ namespace UnitTest // This logic is modeled after NetworkInputArray serialization in the Multiplayer Gem bool SerializeNoDelta(AzNetworking::ISerializer& serializer) { - - for (uint32_t i = 0; i < m_container.size(); ++i) { if(!m_container[i].Serialize(serializer))