From bd5226aac56a6ffe8e05c028e775945e6f591606 Mon Sep 17 00:00:00 2001 From: kberg-amzn Date: Wed, 7 Jul 2021 10:41:44 -0700 Subject: [PATCH 1/3] Changes to fix rewindable attributes incorrectly used on read-only archetype data, fix some bad logic in the pre-render blending code, adding a serializer for AZ::Transform, and adding our client.cfg and server.cfg files to .gitignore Signed-off-by: kberg-amzn --- .gitignore | 2 ++ .../Serialization/AzContainerSerializers.h | 18 ++++++++++++++++++ .../Source/AutoGen/AutoComponent_Header.jinja | 18 +++++++++--------- .../Source/AutoGen/AutoComponent_Source.jinja | 10 +--------- ...NetworkTransformComponent.AutoComponent.xml | 5 ----- .../Code/Source/MultiplayerSystemComponent.cpp | 12 +++++------- 6 files changed, 35 insertions(+), 30 deletions(-) diff --git a/.gitignore b/.gitignore index 664680c5bf..654b839155 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,8 @@ UserSettings.xml FrameCapture/** .DS_Store user*.cfg +client*.cfg +server*.cfg .mayaSwatches/ _savebackup/ #Output folder for test results when running Automated Tests diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/AzContainerSerializers.h b/Code/Framework/AzNetworking/AzNetworking/Serialization/AzContainerSerializers.h index 25b1543b1f..107d0068fb 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Serialization/AzContainerSerializers.h +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/AzContainerSerializers.h @@ -302,4 +302,22 @@ namespace AzNetworking return serializer.IsValid(); } }; + + template <> + struct SerializeObjectHelper + { + static bool SerializeObject(ISerializer& serializer, AZ::Transform& value) + { + AZ::Vector3 translation = value.GetTranslation(); + AZ::Quaternion rotation = value.GetRotation(); + float uniformScale = value.GetUniformScale(); + serializer.Serialize(translation, "Translation"); + serializer.Serialize(rotation, "Rotation"); + serializer.Serialize(uniformScale, "Scale"); + value.SetTranslation(translation); + value.SetRotation(rotation); + value.SetUniformScale(uniformScale); + return serializer.IsValid(); + } + }; } diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja index 79fbb4a99e..4fe2f6291c 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja @@ -8,22 +8,22 @@ {% set PropertyName = UpperFirst(Property.attrib['Name']) %} {% if Property.attrib['Container'] == 'Array' %} {% if Property.attrib['IsRewindable']|booleanTrue %} -const RewindableArray<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}> &Get{{ PropertyName }}Array() const; +const RewindableArray<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& Get{{ PropertyName }}Array() const; {% else %} -const AZStd::array<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}> &Get{{ PropertyName }}Array() const; +const AZStd::array<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& Get{{ PropertyName }}Array() const; {% endif %} -const {{ Property.attrib['Type'] }} &Get{{ PropertyName }}(int32_t index) const; +const {{ Property.attrib['Type'] }}& Get{{ PropertyName }}(int32_t index) const; {% if Property.attrib['GenerateEventBindings']|booleanTrue %} void {{ PropertyName }}AddEvent(AZ::Event::Handler& handler); {% endif %} {% elif Property.attrib['Container'] == 'Vector' %} {% if Property.attrib['IsRewindable']|booleanTrue %} -const RewindableFixedVector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}> &Get{{ PropertyName }}Vector() const; +const RewindableFixedVector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& Get{{ PropertyName }}Vector() const; {% else %} -const AZStd::fixed_vector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}> &Get{{ PropertyName }}Vector() const; +const AZStd::fixed_vector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& Get{{ PropertyName }}Vector() const; {% endif %} -const {{ Property.attrib['Type'] }} &Get{{ PropertyName }}(int32_t index) const; -const {{ Property.attrib['Type'] }} &{{ PropertyName }}GetBack() const; +const {{ Property.attrib['Type'] }}& Get{{ PropertyName }}(int32_t index) const; +const {{ Property.attrib['Type'] }}& {{ PropertyName }}GetBack() const; uint32_t {{ PropertyName }}GetSize() const; {% if Property.attrib['GenerateEventBindings']|booleanTrue %} void {{ PropertyName }}AddEvent(AZ::Event::Handler& handler); @@ -63,7 +63,7 @@ void Set{{ PropertyName }}(const {{ Property.attrib['Type'] }}& value); {% macro DeclareNetworkPropertyGetters(Component, ReplicateFrom, ReplicateTo, IsProtected) %} {% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, ReplicateFrom, ReplicateTo) %} {% set PropertyName = UpperFirst(Property.attrib['Name']) %} -{% if Property.attrib['IsPublic'] | booleanTrue != IsProtected %} +{% if Property.attrib['IsPublic']|booleanTrue != IsProtected %} //! {{ PropertyName }} Accessors //! {{ Property.attrib['Description'] }}. {{ DeclareNetworkPropertyGetter(Property) }} @@ -105,7 +105,7 @@ const {{ Property.attrib['Type'] }}& Get{{ PropertyName }}() const; {% macro DeclareNetworkPropertyAccessors(Component, ReplicateFrom, ReplicateTo, IsProtected) %} {% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, ReplicateFrom, ReplicateTo) %} {% set PropertyName = UpperFirst(Property.attrib['Name']) %} -{% if Property.attrib['IsPublic'] | booleanTrue != IsProtected %} +{% if Property.attrib['IsPublic']|booleanTrue != IsProtected %} //! {{ PropertyName }} Accessors //! {{ Property.attrib['Description'] }}. {{ DeclareNetworkPropertyGetter(Property) -}} diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index c34c639cd9..f1c7098c19 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -507,7 +507,7 @@ case {{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ Upp {% endif %} } {% else %} - Handle{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(rpcParamList) }}); + Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection, {{ ', '.join(rpcParamList) }}); {% endif %} } else if (paramsSerialized) @@ -712,11 +712,7 @@ void {{ ClassName }}::NotifyChanges{{ AutoComponentMacros.GetNetPropertiesSetNam {% macro DefineArchetypePropertyGet(Property, ClassType, ClassName, Prefix = '') %} {% if ClassType == '' or Property.attrib['ExportTo'] == ClassType or Property.attrib['ExportTo'] == "Common" %} {% if Property.attrib['Container'] == 'Array' %} -{% if Property.attrib['IsRewindable']|booleanTrue %} -const RewindableArray<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& {{ ClassName }}::Get{{ UpperFirst(Property.attrib['Name']) }}Array() const -{% else %} const AZStd::array<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& {{ ClassName }}::Get{{ UpperFirst(Property.attrib['Name']) }}Array() const -{% endif %} { return {{ Prefix }}m_{{ LowerFirst(Property.attrib['Name']) }}; } @@ -727,11 +723,7 @@ const {{ Property.attrib['Type'] }}& {{ ClassName }}::Get{{ UpperFirst(Property. } {% elif Property.attrib['Container'] == 'Vector' %} -{% if Property.attrib['IsRewindable']|booleanTrue %} -const RewindableFixedVector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& {{ ClassName }}::Get{{ UpperFirst(Property.attrib['Name']) }}Vector() const -{% else %} const AZStd::fixed_vector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& {{ ClassName }}::Get{{ UpperFirst(Property.attrib['Name']) }}Vector() const -{% endif %} { return {{ Prefix }}m_{{ LowerFirst(Property.attrib['Name']) }}; } diff --git a/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml b/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml index 8abc874aa6..cec005cc26 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml +++ b/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml @@ -18,9 +18,4 @@ - - diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 012eca1e89..93f655af0c 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -847,12 +847,10 @@ namespace Multiplayer void MultiplayerSystemComponent::TickVisibleNetworkEntities(float deltaTime, float serverRateSeconds) { - const float targetAdjustBlend = AZStd::clamp(deltaTime / serverRateSeconds, 0.0f, 1.0f); - m_renderBlendFactor += targetAdjustBlend; - // Linear close to the origin, but asymptote at y = 1 - const float adjustedBlendFactor = 1.0f - (std::pow(0.2f, m_renderBlendFactor)); - AZLOG(NET_Blending, "Computed blend factor of %f", adjustedBlendFactor); + const float targetAdjustBlend = AZStd::clamp(deltaTime / serverRateSeconds, 0.0f, 1.0f); + m_renderBlendFactor = 1.0f - (std::pow(0.2f, m_renderBlendFactor + targetAdjustBlend)); + AZLOG(NET_Blending, "Computed blend factor of %0.2f using a frametime of %0.2f and a serverTickRate of %0.2f", m_renderBlendFactor, deltaTime, serverRateSeconds); if (Camera::ActiveCameraRequestBus::HasHandlers()) { @@ -895,7 +893,7 @@ namespace Multiplayer for (NetBindComponent* netBindComponent : gatheredEntities) { - netBindComponent->NotifyPreRender(deltaTime, adjustedBlendFactor); + netBindComponent->NotifyPreRender(deltaTime, m_renderBlendFactor); } } else @@ -907,7 +905,7 @@ namespace Multiplayer NetBindComponent* netBindComponent = entity->FindComponent(); if (netBindComponent != nullptr) { - netBindComponent->NotifyPreRender(deltaTime, adjustedBlendFactor); + netBindComponent->NotifyPreRender(deltaTime, m_renderBlendFactor); } } } From 23a4835e4814640fe68dc8f310620e5f0c09a359 Mon Sep 17 00:00:00 2001 From: kberg-amzn Date: Mon, 19 Jul 2021 12:03:57 -0700 Subject: [PATCH 2/3] Desync debug work Signed-off-by: kberg-amzn --- .../Serialization/HashSerializer.cpp | 19 +++++++++++-------- .../Components/NetworkTransformComponent.cpp | 6 +++++- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp b/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp index 187dfcdfd0..07cc5f3588 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp @@ -10,9 +10,9 @@ namespace AzNetworking { - // This gives us a hash sensitivity of around 1/128th of a unit, and will detect errors within a range of -16,777,216 to +16,777,216 - static const int32_t FloatHashMinValue = (INT_MIN >> 7); - static const int32_t FloatHashMaxValue = (INT_MAX >> 7); + // This gives us a hash sensitivity of around 1/512th of a unit, and will detect errors within a range of -4,194,304 to +4,194,304 + static const int32_t FloatHashMinValue = (INT_MIN >> 9); + static const int32_t FloatHashMaxValue = (INT_MAX >> 9); AZ::HashValue32 HashSerializer::GetHash() const { @@ -92,11 +92,14 @@ namespace AzNetworking // This hashing serializer is used to detect desyncs between the predicted and authoritative state of all predictive values // If either of these asserts triggers, it means desyncs *will not* be detected for the value being serialized // You should consider using a quantized float for the failing value, or potentially adjust the min/max quantized values - AZ_Assert(value > FloatHashMinValue, "Out of range float value passed to hashing serializer, this will clamp the float value"); - AZ_Assert(value < FloatHashMaxValue, "Out of range float value passed to hashing serializer, this will clamp the float value"); - QuantizedValues<1, 4, FloatHashMinValue, FloatHashMaxValue> quantizedValue(value); - const int32_t hashableValue = quantizedValue.GetQuantizedIntegralValues()[0]; - m_hash = AZ::TypeHash64(hashableValue, m_hash); + //AZ_Assert(value > FloatHashMinValue, "Out of range float value passed to hashing serializer, this will clamp the float value"); + //AZ_Assert(value < FloatHashMaxValue, "Out of range float value passed to hashing serializer, this will clamp the float value"); + //QuantizedValues<1, 4, FloatHashMinValue, FloatHashMaxValue> quantizedValue(value); + //const int32_t hashableValue = quantizedValue.GetQuantizedIntegralValues()[0]; + //m_hash = AZ::TypeHash64(hashableValue, m_hash); + //return true; + + m_hash = AZ::TypeHash64(value, m_hash); return true; } diff --git a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp index e956245724..142d66febb 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp @@ -90,7 +90,11 @@ namespace Multiplayer blendTransform.SetRotation(m_previousTransform.GetRotation().Slerp(m_targetTransform.GetRotation(), blendFactor)); blendTransform.SetTranslation(m_previousTransform.GetTranslation().Lerp(m_targetTransform.GetTranslation(), blendFactor)); blendTransform.SetUniformScale(AZ::Lerp(m_previousTransform.GetUniformScale(), m_targetTransform.GetUniformScale(), blendFactor)); - GetTransformComponent()->SetWorldTM(blendTransform); + + if (!GetTransformComponent()->GetWorldTM().IsClose(blendTransform)) + { + GetTransformComponent()->SetWorldTM(blendTransform); + } } } From 1c004cf882807c33c683e9b809dccd0ed16054dd Mon Sep 17 00:00:00 2001 From: kberg-amzn Date: Tue, 20 Jul 2021 20:54:14 -0700 Subject: [PATCH 3/3] Undo some debug changes in the hashing serializer Signed-off-by: kberg-amzn --- .../AzNetworking/Serialization/HashSerializer.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp b/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp index 22f2bd05fc..23995d44ea 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp @@ -93,14 +93,11 @@ namespace AzNetworking // This hashing serializer is used to detect desyncs between the predicted and authoritative state of all predictive values // If either of these asserts triggers, it means desyncs *will not* be detected for the value being serialized // You should consider using a quantized float for the failing value, or potentially adjust the min/max quantized values - //AZ_Assert(value > FloatHashMinValue, "Out of range float value passed to hashing serializer, this will clamp the float value"); - //AZ_Assert(value < FloatHashMaxValue, "Out of range float value passed to hashing serializer, this will clamp the float value"); - //QuantizedValues<1, 4, FloatHashMinValue, FloatHashMaxValue> quantizedValue(value); - //const int32_t hashableValue = quantizedValue.GetQuantizedIntegralValues()[0]; - //m_hash = AZ::TypeHash64(hashableValue, m_hash); - //return true; - - m_hash = AZ::TypeHash64(value, m_hash); + AZ_Assert(value > FloatHashMinValue, "Out of range float value passed to hashing serializer, this will clamp the float value"); + AZ_Assert(value < FloatHashMaxValue, "Out of range float value passed to hashing serializer, this will clamp the float value"); + QuantizedValues<1, 4, FloatHashMinValue, FloatHashMaxValue> quantizedValue(value); + const int32_t hashableValue = quantizedValue.GetQuantizedIntegralValues()[0]; + m_hash = AZ::TypeHash64(hashableValue, m_hash); return true; }