Merge pull request #3912 from aws-lumberyard-dev/mp_blending_cleanup
NetworkTime cleanup and reworking how network interpolation can be approached
This commit is contained in:
@@ -35,7 +35,7 @@ namespace Multiplayer
|
||||
using EntityMigrationStartEvent = AZ::Event<ClientInputId>;
|
||||
using EntityMigrationEndEvent = AZ::Event<>;
|
||||
using EntityServerMigrationEvent = AZ::Event<const ConstNetworkEntityHandle&, HostId, AzNetworking::ConnectionId>;
|
||||
using EntityPreRenderEvent = AZ::Event<float, float>;
|
||||
using EntityPreRenderEvent = AZ::Event<float>;
|
||||
using EntityCorrectionEvent = AZ::Event<>;
|
||||
|
||||
//! @class NetBindComponent
|
||||
@@ -118,7 +118,7 @@ namespace Multiplayer
|
||||
void NotifyMigrationStart(ClientInputId migratedInputId);
|
||||
void NotifyMigrationEnd();
|
||||
void NotifyServerMigration(HostId hostId, AzNetworking::ConnectionId connectionId);
|
||||
void NotifyPreRender(float deltaTime, float blendFactor);
|
||||
void NotifyPreRender(float deltaTime);
|
||||
void NotifyCorrection();
|
||||
|
||||
void AddEntityStopEventHandler(EntityStopEvent::Handler& eventHandler);
|
||||
|
||||
@@ -29,24 +29,9 @@ namespace Multiplayer
|
||||
void OnDeactivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
|
||||
|
||||
private:
|
||||
void OnPreRender(float deltaTime, float blendFactor);
|
||||
void OnPreRender(float deltaTime);
|
||||
void OnCorrection();
|
||||
|
||||
void OnRotationChangedEvent(const AZ::Quaternion& rotation);
|
||||
void OnTranslationChangedEvent(const AZ::Vector3& translation);
|
||||
void OnScaleChangedEvent(float scale);
|
||||
void OnResetCountChangedEvent();
|
||||
|
||||
void UpdateTargetHostFrameId();
|
||||
|
||||
AZ::Transform m_previousTransform = AZ::Transform::CreateIdentity();
|
||||
AZ::Transform m_targetTransform = AZ::Transform::CreateIdentity();
|
||||
|
||||
AZ::Event<AZ::Quaternion>::Handler m_rotationEventHandler;
|
||||
AZ::Event<AZ::Vector3>::Handler m_translationEventHandler;
|
||||
AZ::Event<float>::Handler m_scaleEventHandler;
|
||||
AZ::Event<uint8_t>::Handler m_resetCountEventHandler;
|
||||
|
||||
EntityPreRenderEvent::Handler m_entityPreRenderEventHandler;
|
||||
EntityCorrectionEvent::Handler m_entityCorrectionEventHandler;
|
||||
|
||||
|
||||
@@ -193,15 +193,13 @@ namespace Multiplayer
|
||||
m_previousHostFrameId = time->GetHostFrameId();
|
||||
m_previousHostTimeMs = time->GetHostTimeMs();
|
||||
m_previousRewindConnectionId = time->GetRewindingConnectionId();
|
||||
time->AlterTime(frameId, timeMs, connectionId);
|
||||
m_previousBlendFactor = time->GetHostBlendFactor();
|
||||
time->AlterBlendFactor(blendFactor);
|
||||
time->AlterTime(frameId, timeMs, blendFactor, connectionId);
|
||||
}
|
||||
inline ~ScopedAlterTime()
|
||||
{
|
||||
INetworkTime* time = GetNetworkTime();
|
||||
time->AlterTime(m_previousHostFrameId, m_previousHostTimeMs, m_previousRewindConnectionId);
|
||||
time->AlterBlendFactor(m_previousBlendFactor);
|
||||
time->AlterTime(m_previousHostFrameId, m_previousHostTimeMs, m_previousBlendFactor, m_previousRewindConnectionId);
|
||||
}
|
||||
private:
|
||||
HostFrameId m_previousHostFrameId = InvalidHostFrameId;
|
||||
|
||||
@@ -52,12 +52,6 @@ namespace Multiplayer
|
||||
//! @return the ConnectionId of the connection requesting the rewind operation
|
||||
virtual AzNetworking::ConnectionId GetRewindingConnectionId() const = 0;
|
||||
|
||||
//! Get the controlling connection that may be currently altering global game time.
|
||||
//! Note this abstraction is required at a relatively high level to allow for 'don't rewind the shooter' semantics
|
||||
//! @param rewindConnectionId if this parameter matches the current rewindConnectionId, it will return the unaltered hostFrameId
|
||||
//! @return the HostFrameId taking into account the provided rewinding connectionId
|
||||
virtual HostFrameId GetHostFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const = 0;
|
||||
|
||||
//! Forcibly sets the current network time to the provided frameId and game time in milliseconds.
|
||||
//! @param frameId the new HostFrameId to use
|
||||
//! @param timeMs the new HostTimeMs to use
|
||||
@@ -66,12 +60,9 @@ namespace Multiplayer
|
||||
//! Alters the current HostFrameId and binds that alteration to the provided ConnectionId.
|
||||
//! @param frameId the new HostFrameId to use
|
||||
//! @param timeMs the new HostTimeMs to use
|
||||
//! @param blendFactor the factor used to blend between values at the current and previous HostFrameId
|
||||
//! @param rewindConnectionId the rewinding ConnectionId
|
||||
virtual void AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId rewindConnectionId) = 0;
|
||||
|
||||
//! Alters the current Host blend factor. Used to drive interpolation in rewound states.
|
||||
//! @param blendFactor the blend factor to use
|
||||
virtual void AlterBlendFactor(float blendFactor) = 0;
|
||||
virtual void AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, float blendFactor, AzNetworking::ConnectionId rewindConnectionId) = 0;
|
||||
|
||||
//! Syncs all entities contained within a volume to the current rewind state.
|
||||
//! @param rewindVolume the volume to rewind entities within (needed for physics entities)
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace Multiplayer
|
||||
//! @return value in const base type form
|
||||
const BASE_TYPE& Get() const;
|
||||
|
||||
//! Const base type retriever for one host frame behind Get(). Only intended for use in SyncRewind contexts.
|
||||
//! Const base type retriever for one host frame behind Get() when contextually appropriate, otherwise identical to Get().
|
||||
//! @return value in const base type form
|
||||
const BASE_TYPE& GetPrevious() const;
|
||||
|
||||
@@ -86,9 +86,13 @@ namespace Multiplayer
|
||||
private:
|
||||
|
||||
//! Returns what the appropriate current time is for this rewindable property.
|
||||
//! @return the appropriate current time is for this rewindable property
|
||||
//! @return the appropriate current time for this rewindable property
|
||||
HostFrameId GetCurrentTimeForProperty() const;
|
||||
|
||||
//! Returns what the appropriate previous time is for this rewindable property.
|
||||
//! @return the appropriate previous time for this rewindable property
|
||||
HostFrameId GetPreviousTimeForProperty() const;
|
||||
|
||||
//! Updates the latest value for this object instance, if frameTime represents a current or future time.
|
||||
//! Any attempts to set old values on the object will fail
|
||||
//! @param value the new value to set in the object history
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace Multiplayer
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline const BASE_TYPE& RewindableObject<BASE_TYPE, REWIND_SIZE>::GetPrevious() const
|
||||
{
|
||||
return GetValueForTime(GetCurrentTimeForProperty() - HostFrameId(1));
|
||||
return GetValueForTime(GetPreviousTimeForProperty());
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
@@ -118,7 +118,22 @@ namespace Multiplayer
|
||||
inline HostFrameId RewindableObject<BASE_TYPE, REWIND_SIZE>::GetCurrentTimeForProperty() const
|
||||
{
|
||||
INetworkTime* networkTime = Multiplayer::GetNetworkTime();
|
||||
return networkTime->GetHostFrameIdForRewindingConnection(m_owningConnectionId);
|
||||
if (networkTime->IsTimeRewound() && (m_owningConnectionId == networkTime->GetRewindingConnectionId()))
|
||||
{
|
||||
return networkTime->GetUnalteredHostFrameId();
|
||||
}
|
||||
return networkTime->GetHostFrameId();
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline HostFrameId RewindableObject<BASE_TYPE, REWIND_SIZE>::GetPreviousTimeForProperty() const
|
||||
{
|
||||
INetworkTime* networkTime = Multiplayer::GetNetworkTime();
|
||||
if (networkTime->IsTimeRewound() && (m_owningConnectionId == networkTime->GetRewindingConnectionId()))
|
||||
{
|
||||
return networkTime->GetUnalteredHostFrameId();
|
||||
}
|
||||
return networkTime->GetHostFrameId() - HostFrameId(1);
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
|
||||
@@ -7,21 +7,21 @@
|
||||
{% macro DeclareNetworkPropertyGetter(Property) %}
|
||||
{% set PropertyName = UpperFirst(Property.attrib['Name']) %}
|
||||
{% if Property.attrib['Container'] == 'Array' %}
|
||||
{% if Property.attrib['IsRewindable']|booleanTrue %}
|
||||
{% if Property.attrib['IsRewindable']|booleanTrue %}
|
||||
const RewindableArray<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& Get{{ PropertyName }}Array() const;
|
||||
{% else %}
|
||||
{% else %}
|
||||
const AZStd::array<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& Get{{ PropertyName }}Array() const;
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
const {{ Property.attrib['Type'] }}& Get{{ PropertyName }}(int32_t index) const;
|
||||
{% if Property.attrib['GenerateEventBindings']|booleanTrue %}
|
||||
void {{ PropertyName }}AddEvent(AZ::Event<int32_t, {{ Property.attrib['Type'] }}>::Handler& handler);
|
||||
{% endif %}
|
||||
{% elif Property.attrib['Container'] == 'Vector' %}
|
||||
{% if Property.attrib['IsRewindable']|booleanTrue %}
|
||||
{% if Property.attrib['IsRewindable']|booleanTrue %}
|
||||
const RewindableFixedVector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& Get{{ PropertyName }}Vector() const;
|
||||
{% else %}
|
||||
{% else %}
|
||||
const AZStd::fixed_vector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& Get{{ PropertyName }}Vector() const;
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
const {{ Property.attrib['Type'] }}& Get{{ PropertyName }}(int32_t index) const;
|
||||
const {{ Property.attrib['Type'] }}& {{ PropertyName }}GetBack() const;
|
||||
uint32_t {{ PropertyName }}GetSize() const;
|
||||
@@ -31,6 +31,9 @@ void {{ PropertyName }}SizeChangedAddEvent(AZ::Event<uint32_t>::Handler& handler
|
||||
{% endif %}
|
||||
{% else %}
|
||||
const {{ Property.attrib['Type'] }}& Get{{ PropertyName }}() const;
|
||||
{% if Property.attrib['IsRewindable']|booleanTrue %}
|
||||
const {{ Property.attrib['Type'] }}& Get{{ PropertyName }}Previous() const;
|
||||
{% endif %}
|
||||
{% if Property.attrib['GenerateEventBindings']|booleanTrue %}
|
||||
void {{ PropertyName }}AddEvent(AZ::Event<{{ Property.attrib['Type'] }}>::Handler& handler);
|
||||
{% endif %}
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
{% macro LowerFirst(text) %}{{ text[0] | lower}}{{ text[1:] }}{% endmacro %}
|
||||
{% macro DefineNetworkPropertyGet(ClassName, Property, Prefix = '') %}
|
||||
{% if Property.attrib['Container'] == 'Array' %}
|
||||
{% if Property.attrib['IsRewindable']|booleanTrue %}
|
||||
{% if Property.attrib['IsRewindable']|booleanTrue %}
|
||||
const RewindableArray<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& {{ ClassName }}::Get{{ UpperFirst(Property.attrib['Name']) }}Array() const
|
||||
{% else %}
|
||||
{% else %}
|
||||
const AZStd::array<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& {{ ClassName }}::Get{{ UpperFirst(Property.attrib['Name']) }}Array() const
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{
|
||||
return {{ Prefix }}m_{{ LowerFirst(Property.attrib['Name']) }};
|
||||
}
|
||||
@@ -25,11 +25,11 @@ void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}AddEvent(AZ::Even
|
||||
|
||||
{% endif %}
|
||||
{% elif Property.attrib['Container'] == 'Vector' %}
|
||||
{% if Property.attrib['IsRewindable']|booleanTrue %}
|
||||
{% if Property.attrib['IsRewindable']|booleanTrue %}
|
||||
const RewindableFixedVector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& {{ ClassName }}::Get{{ UpperFirst(Property.attrib['Name']) }}Vector() const
|
||||
{% else %}
|
||||
{% else %}
|
||||
const AZStd::fixed_vector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& {{ ClassName }}::Get{{ UpperFirst(Property.attrib['Name']) }}Vector() const
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{
|
||||
return {{ Prefix }}m_{{ LowerFirst(Property.attrib['Name']) }};
|
||||
}
|
||||
@@ -68,7 +68,12 @@ const {{ Property.attrib['Type'] }}& {{ ClassName }}::Get{{ UpperFirst(Property.
|
||||
{
|
||||
return {{ Prefix }}m_{{ LowerFirst(Property.attrib['Name']) }};
|
||||
}
|
||||
|
||||
{% if Property.attrib['IsRewindable']|booleanTrue %}
|
||||
const {{ Property.attrib['Type'] }}& {{ ClassName }}::Get{{ UpperFirst(Property.attrib['Name']) }}Previous() const
|
||||
{
|
||||
return {{ Prefix }}m_{{ LowerFirst(Property.attrib['Name']) }}.GetPrevious();
|
||||
}
|
||||
{% endif %}
|
||||
{% if Property.attrib['GenerateEventBindings']|booleanTrue %}
|
||||
void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}AddEvent(AZ::Event<{{ Property.attrib['Type'] }}>::Handler& handler)
|
||||
{
|
||||
|
||||
@@ -32,11 +32,11 @@
|
||||
<Packet Name="EntityUpdates" Desc="A packet that contains multiple entity updates">
|
||||
<Member Type="AZ::TimeMs" Name="hostTimeMs" Init="AZ::TimeMs{ 0 }" />
|
||||
<Member Type="Multiplayer::HostFrameId" Name="hostFrameId" Init="Multiplayer::InvalidHostFrameId" />
|
||||
<Member Type="Multiplayer::NetworkEntityUpdateMessage" Name="entityMessages" Container="Vector" Count="Multiplayer::MaxAggregateEntityMessages" SuppressFromInitializerList="true" />
|
||||
<Member Type="Multiplayer::NetworkEntityUpdateMessage" Name="entityMessages" Container="Vector" Count="Multiplayer::MaxAggregateEntityMessages" />
|
||||
</Packet>
|
||||
|
||||
<Packet Name="EntityRpcs" Desc="A packet that contains multiple entity rpcs">
|
||||
<Member Type="Multiplayer::NetworkEntityRpcMessage" Name="entityRpcs" Container="Vector" Count="Multiplayer::MaxAggregateRpcMessages" SuppressFromInitializerList="true" />
|
||||
<Member Type="Multiplayer::NetworkEntityRpcMessage" Name="entityRpcs" Container="Vector" Count="Multiplayer::MaxAggregateRpcMessages" />
|
||||
</Packet>
|
||||
|
||||
<Packet Name="ClientMigration" Desc="Tell a client to migrate to a new server">
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
|
||||
<Include File="Multiplayer/MultiplayerTypes.h"/>
|
||||
|
||||
<NetworkProperty Type="AZ::Quaternion" Name="rotation" Init="AZ::Quaternion::CreateIdentity()" ReplicateFrom="Authority" ReplicateTo="Client" IsRewindable="true" IsPredictable="true" IsPublic="true" Container="Object" ExposeToEditor="false" ExposeToScript="false" GenerateEventBindings="true" />
|
||||
<NetworkProperty Type="AZ::Quaternion" Name="rotation" Init="AZ::Quaternion::CreateIdentity()" ReplicateFrom="Authority" ReplicateTo="Client" IsRewindable="true" IsPredictable="true" IsPublic="true" Container="Object" ExposeToEditor="false" ExposeToScript="false" GenerateEventBindings="false" />
|
||||
<NetworkProperty Type="AZ::Vector3" Name="translation" Init="AZ::Vector3::CreateZero()" ReplicateFrom="Authority" ReplicateTo="Client" IsRewindable="true" IsPredictable="true" IsPublic="true" Container="Object" ExposeToEditor="false" ExposeToScript="false" GenerateEventBindings="true" />
|
||||
<NetworkProperty Type="float" Name="scale" Init="1.0f" ReplicateFrom="Authority" ReplicateTo="Client" IsRewindable="true" IsPredictable="true" IsPublic="true" Container="Object" ExposeToEditor="false" ExposeToScript="false" GenerateEventBindings="true" />
|
||||
<NetworkProperty Type="float" Name="scale" Init="1.0f" ReplicateFrom="Authority" ReplicateTo="Client" IsRewindable="true" IsPredictable="true" IsPublic="true" Container="Object" ExposeToEditor="false" ExposeToScript="false" GenerateEventBindings="false" />
|
||||
<NetworkProperty Type="uint8_t" Name="resetCount" Init="0" ReplicateFrom="Authority" ReplicateTo="Client" IsRewindable="false" IsPredictable="true" IsPublic="true" Container="Object" ExposeToEditor="false" ExposeToScript="false" GenerateEventBindings="true" />
|
||||
<NetworkProperty Type="NetEntityId" Name="parentEntityId" Init="InvalidNetEntityId" ReplicateFrom="Authority" ReplicateTo="Client" IsRewindable="true" IsPredictable="true" IsPublic="true" Container="Object" ExposeToEditor="false" ExposeToScript="false" GenerateEventBindings="true" />
|
||||
<NetworkProperty Type="int32_t" Name="parentAttachmentBoneId" Init="-1" ReplicateFrom="Authority" ReplicateTo="Client" IsRewindable="true" IsPredictable="true" IsPublic="true" Container="Object" ExposeToEditor="false" ExposeToScript="false" GenerateEventBindings="true" />
|
||||
|
||||
@@ -185,12 +185,9 @@ namespace Multiplayer
|
||||
// Discard move input events, client may be speed hacking
|
||||
if (m_clientBankedTime < sv_MaxBankTimeWindowSec)
|
||||
{
|
||||
// Client blends from previous frame to target so here we subtract blend factor to get to that state
|
||||
const float blendFactor = AZStd::min(AZStd::max(0.f, input.GetHostBlendFactor()), 1.0f);
|
||||
const AZ::TimeMs blendMs = AZ::TimeMs(static_cast<float>(static_cast<AZ::TimeMs>(cl_InputRateMs)) * (1.0f - blendFactor));
|
||||
m_clientBankedTime = AZStd::min(m_clientBankedTime + clientInputRateSec, (double)sv_MaxBankTimeWindowSec); // clamp to boundary
|
||||
{
|
||||
ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs() - blendMs, input.GetHostBlendFactor(), invokingConnection->GetConnectionId());
|
||||
ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), input.GetHostBlendFactor(), invokingConnection->GetConnectionId());
|
||||
GetNetBindComponent()->ProcessInput(input, static_cast<float>(clientInputRateSec));
|
||||
}
|
||||
|
||||
@@ -436,10 +433,13 @@ namespace Multiplayer
|
||||
|
||||
NetworkInputArray inputArray(GetEntityHandle());
|
||||
NetworkInput& input = inputArray[0];
|
||||
const float blendFactor = AZStd::min(AZStd::max(0.f, multiplayer->GetCurrentBlendFactor()), 1.0f);
|
||||
const AZ::TimeMs blendMs = AZ::TimeMs(static_cast<float>(static_cast<AZ::TimeMs>(cl_InputRateMs)) * (1.0f - blendFactor));
|
||||
|
||||
input.SetClientInputId(m_clientInputId);
|
||||
input.SetHostFrameId(networkTime->GetHostFrameId());
|
||||
input.SetHostTimeMs(multiplayer->GetCurrentHostTimeMs());
|
||||
// Account for the client blending from previous frame to current
|
||||
input.SetHostTimeMs(multiplayer->GetCurrentHostTimeMs() - blendMs);
|
||||
input.SetHostBlendFactor(multiplayer->GetCurrentBlendFactor());
|
||||
|
||||
// Allow components to form the input for this frame
|
||||
|
||||
@@ -405,9 +405,9 @@ namespace Multiplayer
|
||||
m_entityServerMigrationEvent.Signal(m_netEntityHandle, hostId, connectionId);
|
||||
}
|
||||
|
||||
void NetBindComponent::NotifyPreRender(float deltaTime, float blendFactor)
|
||||
void NetBindComponent::NotifyPreRender(float deltaTime)
|
||||
{
|
||||
m_entityPreRenderEvent.Signal(deltaTime, blendFactor);
|
||||
m_entityPreRenderEvent.Signal(deltaTime);
|
||||
}
|
||||
|
||||
void NetBindComponent::NotifyCorrection()
|
||||
|
||||
@@ -26,11 +26,7 @@ namespace Multiplayer
|
||||
}
|
||||
|
||||
NetworkTransformComponent::NetworkTransformComponent()
|
||||
: m_rotationEventHandler([this](const AZ::Quaternion& rotation) { OnRotationChangedEvent(rotation); })
|
||||
, m_translationEventHandler([this](const AZ::Vector3& translation) { OnTranslationChangedEvent(translation); })
|
||||
, m_scaleEventHandler([this](float scale) { OnScaleChangedEvent(scale); })
|
||||
, m_resetCountEventHandler([this](const uint8_t&) { OnResetCountChangedEvent(); })
|
||||
, m_entityPreRenderEventHandler([this](float deltaTime, float blendFactor) { OnPreRender(deltaTime, blendFactor); })
|
||||
: m_entityPreRenderEventHandler([this](float deltaTime) { OnPreRender(deltaTime); })
|
||||
, m_entityCorrectionEventHandler([this]() { OnCorrection(); })
|
||||
{
|
||||
;
|
||||
@@ -43,15 +39,8 @@ namespace Multiplayer
|
||||
|
||||
void NetworkTransformComponent::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
|
||||
{
|
||||
RotationAddEvent(m_rotationEventHandler);
|
||||
TranslationAddEvent(m_translationEventHandler);
|
||||
ScaleAddEvent(m_scaleEventHandler);
|
||||
ResetCountAddEvent(m_resetCountEventHandler);
|
||||
GetNetBindComponent()->AddEntityPreRenderEventHandler(m_entityPreRenderEventHandler);
|
||||
GetNetBindComponent()->AddEntityCorrectionEventHandler(m_entityCorrectionEventHandler);
|
||||
|
||||
// When coming into relevance, reset all blending factors so we don't interpolate to our start position
|
||||
OnResetCountChangedEvent();
|
||||
}
|
||||
|
||||
void NetworkTransformComponent::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
|
||||
@@ -59,59 +48,31 @@ namespace Multiplayer
|
||||
;
|
||||
}
|
||||
|
||||
void NetworkTransformComponent::OnRotationChangedEvent(const AZ::Quaternion& rotation)
|
||||
{
|
||||
m_previousTransform.SetRotation(m_targetTransform.GetRotation());
|
||||
m_targetTransform.SetRotation(rotation);
|
||||
UpdateTargetHostFrameId();
|
||||
}
|
||||
|
||||
void NetworkTransformComponent::OnTranslationChangedEvent(const AZ::Vector3& translation)
|
||||
{
|
||||
m_previousTransform.SetTranslation(m_targetTransform.GetTranslation());
|
||||
m_targetTransform.SetTranslation(translation);
|
||||
UpdateTargetHostFrameId();
|
||||
}
|
||||
|
||||
void NetworkTransformComponent::OnScaleChangedEvent(float scale)
|
||||
{
|
||||
m_previousTransform.SetUniformScale(m_targetTransform.GetUniformScale());
|
||||
m_targetTransform.SetUniformScale(scale);
|
||||
UpdateTargetHostFrameId();
|
||||
}
|
||||
|
||||
void NetworkTransformComponent::OnResetCountChangedEvent()
|
||||
{
|
||||
m_targetTransform.SetRotation(GetRotation());
|
||||
m_targetTransform.SetTranslation(GetTranslation());
|
||||
m_targetTransform.SetUniformScale(GetScale());
|
||||
m_previousTransform = m_targetTransform;
|
||||
}
|
||||
|
||||
void NetworkTransformComponent::UpdateTargetHostFrameId()
|
||||
{
|
||||
HostFrameId currentHostFrameId = Multiplayer::GetNetworkTime()->GetHostFrameId();
|
||||
if (currentHostFrameId > m_targetHostFrameId)
|
||||
{
|
||||
m_targetHostFrameId = currentHostFrameId;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkTransformComponent::OnPreRender([[maybe_unused]] float deltaTime, float blendFactor)
|
||||
void NetworkTransformComponent::OnPreRender([[maybe_unused]] float deltaTime)
|
||||
{
|
||||
if (!HasController())
|
||||
{
|
||||
AZ::Transform blendTransform;
|
||||
if (Multiplayer::GetNetworkTime() && Multiplayer::GetNetworkTime()->GetHostFrameId() > m_targetHostFrameId)
|
||||
blendTransform.SetRotation(GetRotation());
|
||||
blendTransform.SetTranslation(GetTranslation());
|
||||
blendTransform.SetUniformScale(GetScale());
|
||||
|
||||
const float blendFactor = GetMultiplayer()->GetCurrentBlendFactor();
|
||||
if (!AZ::IsClose(blendFactor, 1.0f))
|
||||
{
|
||||
m_previousTransform = m_targetTransform;
|
||||
blendTransform = m_targetTransform;
|
||||
}
|
||||
else
|
||||
{
|
||||
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));
|
||||
AZ::Transform blendTransformPrevious;
|
||||
blendTransformPrevious.SetRotation(GetRotationPrevious());
|
||||
blendTransformPrevious.SetTranslation(GetTranslationPrevious());
|
||||
blendTransformPrevious.SetUniformScale(GetScalePrevious());
|
||||
|
||||
if (!blendTransform.IsClose(blendTransformPrevious))
|
||||
{
|
||||
blendTransform.SetRotation(blendTransformPrevious.GetRotation().Slerp(blendTransform.GetRotation(), blendFactor));
|
||||
blendTransform.SetTranslation(
|
||||
blendTransformPrevious.GetTranslation().Lerp(blendTransform.GetTranslation(), blendFactor));
|
||||
blendTransform.SetUniformScale(
|
||||
AZ::Lerp(blendTransformPrevious.GetUniformScale(), blendTransform.GetUniformScale(), blendFactor));
|
||||
}
|
||||
}
|
||||
|
||||
if (!GetTransformComponent()->GetWorldTM().IsClose(blendTransform))
|
||||
@@ -124,12 +85,15 @@ namespace Multiplayer
|
||||
void NetworkTransformComponent::OnCorrection()
|
||||
{
|
||||
// Snap to latest
|
||||
OnResetCountChangedEvent();
|
||||
AZ::Transform targetTransform;
|
||||
targetTransform.SetRotation(GetRotation());
|
||||
targetTransform.SetTranslation(GetTranslation());
|
||||
targetTransform.SetUniformScale(GetScale());
|
||||
|
||||
// Hard set the entities transform
|
||||
if (!GetTransformComponent()->GetWorldTM().IsClose(m_targetTransform))
|
||||
if (!GetTransformComponent()->GetWorldTM().IsClose(targetTransform))
|
||||
{
|
||||
GetTransformComponent()->SetWorldTM(m_targetTransform);
|
||||
GetTransformComponent()->SetWorldTM(targetTransform);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -922,7 +922,7 @@ namespace Multiplayer
|
||||
|
||||
for (NetBindComponent* netBindComponent : gatheredEntities)
|
||||
{
|
||||
netBindComponent->NotifyPreRender(deltaTime, m_renderBlendFactor);
|
||||
netBindComponent->NotifyPreRender(deltaTime);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -934,7 +934,7 @@ namespace Multiplayer
|
||||
NetBindComponent* netBindComponent = entity->FindComponent<NetBindComponent>();
|
||||
if (netBindComponent != nullptr)
|
||||
{
|
||||
netBindComponent->NotifyPreRender(deltaTime, m_renderBlendFactor);
|
||||
netBindComponent->NotifyPreRender(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,11 +65,6 @@ namespace Multiplayer
|
||||
return m_rewindingConnectionId;
|
||||
}
|
||||
|
||||
HostFrameId NetworkTime::GetHostFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const
|
||||
{
|
||||
return (IsTimeRewound() && (rewindConnectionId == m_rewindingConnectionId)) ? m_unalteredFrameId : m_hostFrameId;
|
||||
}
|
||||
|
||||
void NetworkTime::ForceSetTime(HostFrameId frameId, AZ::TimeMs timeMs)
|
||||
{
|
||||
AZ_Assert(!IsTimeRewound(), "Forcibly setting network time is unsupported under a rewound time scope");
|
||||
@@ -79,16 +74,12 @@ namespace Multiplayer
|
||||
m_rewindingConnectionId = AzNetworking::InvalidConnectionId;
|
||||
}
|
||||
|
||||
void NetworkTime::AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId rewindConnectionId)
|
||||
void NetworkTime::AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, float blendFactor, AzNetworking::ConnectionId rewindConnectionId)
|
||||
{
|
||||
m_hostFrameId = frameId;
|
||||
m_hostTimeMs = timeMs;
|
||||
m_rewindingConnectionId = rewindConnectionId;
|
||||
}
|
||||
|
||||
void NetworkTime::AlterBlendFactor(float blendFactor)
|
||||
{
|
||||
m_hostBlendFactor = blendFactor;
|
||||
m_rewindingConnectionId = rewindConnectionId;
|
||||
}
|
||||
|
||||
void NetworkTime::SyncEntitiesToRewindState(const AZ::Aabb& rewindVolume)
|
||||
@@ -121,8 +112,15 @@ namespace Multiplayer
|
||||
|
||||
if (networkTransform != nullptr)
|
||||
{
|
||||
// We're not presently factoring in interpolated position here
|
||||
const AZ::Vector3 rewindCenter = networkTransform->GetTranslation(); // Get the rewound position
|
||||
// Get the rewound position for target host frame ID plus the one preceding it for potential lerp
|
||||
AZ::Vector3 rewindCenter = networkTransform->GetTranslation();
|
||||
const AZ::Vector3 rewindCenterPrevious = networkTransform->GetTranslationPrevious();
|
||||
const float blendFactor = GetNetworkTime()->GetHostBlendFactor();
|
||||
if (!AZ::IsClose(blendFactor, 1.0f) && !rewindCenter.IsClose(rewindCenterPrevious))
|
||||
{
|
||||
// If we have a blend factor, lerp the translation for accuracy
|
||||
rewindCenter = rewindCenterPrevious.Lerp(rewindCenter, blendFactor);
|
||||
}
|
||||
const AZ::Vector3 rewindOffset = rewindCenter - currentCenter; // Compute offset between rewound and current positions
|
||||
const AZ::Aabb rewoundAabb = currentBounds.GetTranslated(rewindOffset); // Apply offset to the entity aabb
|
||||
|
||||
|
||||
@@ -32,10 +32,8 @@ namespace Multiplayer
|
||||
AZ::TimeMs GetHostTimeMs() const override;
|
||||
float GetHostBlendFactor() const override;
|
||||
AzNetworking::ConnectionId GetRewindingConnectionId() const override;
|
||||
HostFrameId GetHostFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const override;
|
||||
void ForceSetTime(HostFrameId frameId, AZ::TimeMs timeMs) override;
|
||||
void AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId rewindConnectionId) override;
|
||||
void AlterBlendFactor(float blendFactor) override;
|
||||
void AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, float blendFactor, AzNetworking::ConnectionId rewindConnectionId) override;
|
||||
void SyncEntitiesToRewindState(const AZ::Aabb& rewindVolume) override;
|
||||
void ClearRewoundEntities() override;
|
||||
//! @}
|
||||
|
||||
@@ -57,6 +57,35 @@ namespace UnitTest
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RewindableObjectTests, CurrentPreviousTests)
|
||||
{
|
||||
Multiplayer::RewindableObject<uint32_t, RewindableBufferFrames> test(0);
|
||||
|
||||
for (uint32_t i = 0; i < RewindableBufferFrames; ++i)
|
||||
{
|
||||
test = i;
|
||||
EXPECT_EQ(i, test);
|
||||
Multiplayer::GetNetworkTime()->IncrementHostFrameId();
|
||||
}
|
||||
|
||||
{
|
||||
// Test that Get/GetPrevious return different value when not on the owning connection
|
||||
Multiplayer::ScopedAlterTime time(static_cast<Multiplayer::HostFrameId>(RewindableBufferFrames - 1), AZ::TimeMs{ 0 }, 1.f, AzNetworking::InvalidConnectionId);
|
||||
EXPECT_EQ(RewindableBufferFrames - 1, test.Get());
|
||||
EXPECT_EQ(RewindableBufferFrames - 2, test.GetPrevious());
|
||||
}
|
||||
|
||||
// Test that Get/GetPrevious return the unaltered frame on the owning conection
|
||||
Multiplayer::GetNetworkTime()->AlterTime(static_cast<Multiplayer::HostFrameId>(RewindableBufferFrames - 1), AZ::TimeMs{ 0 }, 1.f, AzNetworking::ConnectionId(0));
|
||||
{
|
||||
Multiplayer::ScopedAlterTime time(static_cast<Multiplayer::HostFrameId>(RewindableBufferFrames - 1), AZ::TimeMs{ 0 }, 1.f, AzNetworking::ConnectionId(0));
|
||||
test.SetOwningConnectionId(AzNetworking::ConnectionId(0));
|
||||
EXPECT_EQ(RewindableBufferFrames - 1, test.Get());
|
||||
EXPECT_EQ(RewindableBufferFrames - 1, test.GetPrevious());
|
||||
}
|
||||
Multiplayer::GetNetworkTime()->AlterTime(static_cast<Multiplayer::HostFrameId>(RewindableBufferFrames), AZ::TimeMs(0), 1.f, AzNetworking::InvalidConnectionId);
|
||||
}
|
||||
|
||||
TEST_F(RewindableObjectTests, OverflowTests)
|
||||
{
|
||||
Multiplayer::RewindableObject<uint32_t, RewindableBufferFrames> test(0);
|
||||
|
||||
Reference in New Issue
Block a user