Moving NetworkHitVolumesComponent and NetworkRigidBodyComponent to the MultiplayerGem
Signed-off-by: Gene Walters <genewalt@amazon.com>
This commit is contained in:
@@ -25,6 +25,8 @@ ly_add_target(
|
||||
AZ::AzCore
|
||||
AZ::AzFramework
|
||||
AZ::AzNetworking
|
||||
PRIVATE
|
||||
Gem::EMotionFXStaticLib
|
||||
AUTOGEN_RULES
|
||||
*.AutoPackets.xml,AutoPackets_Header.jinja,$path/$fileprefix.AutoPackets.h
|
||||
*.AutoPackets.xml,AutoPackets_Inline.jinja,$path/$fileprefix.AutoPackets.inl
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Source/AutoGen/NetworkHitVolumesComponent.AutoComponent.h>
|
||||
#include <Multiplayer/Components/NetBindComponent.h>
|
||||
#include <Integration/ActorComponentBus.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
|
||||
namespace Physics
|
||||
{
|
||||
class CharacterRequests;
|
||||
class CharacterHitDetectionConfiguration;
|
||||
}
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
class NetworkHitVolumesComponent
|
||||
: public NetworkHitVolumesComponentBase
|
||||
, private EMotionFX::Integration::ActorComponentNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
struct AnimatedHitVolume final
|
||||
{
|
||||
AnimatedHitVolume
|
||||
(
|
||||
AzNetworking::ConnectionId connectionId,
|
||||
Physics::CharacterRequests* character,
|
||||
const char* hitVolumeName,
|
||||
const Physics::ColliderConfiguration* colliderConfig,
|
||||
const Physics::ShapeConfiguration* shapeConfig,
|
||||
const uint32_t jointIndex
|
||||
);
|
||||
|
||||
~AnimatedHitVolume() = default;
|
||||
|
||||
void UpdateTransform(const AZ::Transform& transform);
|
||||
void SyncToCurrentTransform();
|
||||
|
||||
Multiplayer::RewindableObject<AZ::Transform, Multiplayer::RewindHistorySize> m_transform;
|
||||
AZStd::shared_ptr<Physics::Shape> m_physicsShape;
|
||||
|
||||
// Cached so we don't have to do subsequent lookups by name
|
||||
const Physics::ColliderConfiguration* m_colliderConfig = nullptr;
|
||||
const Physics::ShapeConfiguration* m_shapeConfig = nullptr;
|
||||
AZ::Transform m_colliderOffSetTransform;
|
||||
const AZ::u32 m_jointIndex = 0;
|
||||
};
|
||||
|
||||
AZ_MULTIPLAYER_COMPONENT(Multiplayer::NetworkHitVolumesComponent, s_networkHitVolumesComponentConcreteUuid, Multiplayer::NetworkHitVolumesComponentBase);
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
NetworkHitVolumesComponent();
|
||||
|
||||
void OnInit() override;
|
||||
void OnActivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
|
||||
void OnDeactivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
|
||||
|
||||
private:
|
||||
void OnPreRender(float deltaTime, float blendFactor);
|
||||
void OnTransformUpdate(const AZ::Transform& transform);
|
||||
void OnSyncRewind();
|
||||
|
||||
void CreateHitVolumes();
|
||||
void DestroyHitVolumes();
|
||||
|
||||
//! ActorComponentNotificationBus::Handler
|
||||
//! @{
|
||||
void OnActorInstanceCreated(EMotionFX::ActorInstance* actorInstance) override;
|
||||
void OnActorInstanceDestroyed(EMotionFX::ActorInstance* actorInstance) override;
|
||||
//! @}
|
||||
|
||||
Physics::CharacterRequests* m_physicsCharacter = nullptr;
|
||||
EMotionFX::Integration::ActorComponentRequests* m_actorComponent = nullptr;
|
||||
const Physics::CharacterColliderConfiguration* m_hitDetectionConfig = nullptr;
|
||||
|
||||
AZStd::vector<AnimatedHitVolume> m_animatedHitVolumes;
|
||||
|
||||
Multiplayer::EntitySyncRewindEvent::Handler m_syncRewindHandler;
|
||||
Multiplayer::EntityPreRenderEvent::Handler m_preRenderHandler;
|
||||
AZ::TransformChangedEvent::Handler m_transformChangedHandler;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <Source/AutoGen/NetworkRigidBodyComponent.AutoComponent.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <Multiplayer/Components/NetBindComponent.h>
|
||||
|
||||
namespace Physics
|
||||
{
|
||||
class RigidBodyRequests;
|
||||
}
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
//! Bus for requests to the network rigid body component.
|
||||
class NetworkRigidBodyRequests : public AZ::ComponentBus
|
||||
{
|
||||
};
|
||||
using NetworkRigidBodyRequestBus = AZ::EBus<NetworkRigidBodyRequests>;
|
||||
|
||||
class NetworkRigidBodyComponent final
|
||||
: public NetworkRigidBodyComponentBase
|
||||
, private NetworkRigidBodyRequestBus::Handler
|
||||
{
|
||||
friend class NetworkRigidBodyComponentController;
|
||||
|
||||
public:
|
||||
AZ_MULTIPLAYER_COMPONENT(
|
||||
Multiplayer::NetworkRigidBodyComponent, s_networkRigidBodyComponentConcreteUuid, Multiplayer::NetworkRigidBodyComponentBase);
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
||||
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
|
||||
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
|
||||
|
||||
NetworkRigidBodyComponent();
|
||||
|
||||
void OnInit() override;
|
||||
void OnActivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
|
||||
void OnDeactivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
|
||||
|
||||
private:
|
||||
void OnTransformUpdate(const AZ::Transform& worldTm);
|
||||
void OnSyncRewind();
|
||||
|
||||
Multiplayer::EntitySyncRewindEvent::Handler m_syncRewindHandler;
|
||||
AZ::TransformChangedEvent::Handler m_transformChangedHandler;
|
||||
Physics::RigidBodyRequests* m_physicsRigidBodyComponent = nullptr;
|
||||
Multiplayer::RewindableObject<AZ::Transform, Multiplayer::RewindHistorySize> m_transform;
|
||||
};
|
||||
|
||||
class NetworkRigidBodyComponentController
|
||||
: public NetworkRigidBodyComponentControllerBase
|
||||
{
|
||||
public:
|
||||
NetworkRigidBodyComponentController(NetworkRigidBodyComponent& parent);
|
||||
|
||||
void OnActivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
|
||||
void OnDeactivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
|
||||
|
||||
void HandleSendApplyImpulse(AzNetworking::IConnection* invokingConnection, const AZ::Vector3& impulse, const AZ::Vector3& worldPoint) override;
|
||||
};
|
||||
} // namespace Multiplayer
|
||||
@@ -14,7 +14,7 @@
|
||||
{% set Namespace = dataFiles[0].attrib['Namespace'] %}
|
||||
{% for Component in dataFiles %}
|
||||
{% if Component.attrib['Namespace'] != Namespace %}
|
||||
#error "mismatched component namespaces detected in declared multiplayer components, expected {{ Namespace }} but found {{ Component.attrib['Namespace'] }}"
|
||||
#error "mismatched component namespaces detected in declared multiplayer components, expected {{ Namespace }} but {{ Component.attrib['Name'] }} is using {{ Component.attrib['Namespace'] }} namespace."
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
namespace {{ Namespace }}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<Component
|
||||
Name="NetworkHitVolumesComponent"
|
||||
Namespace="Multiplayer"
|
||||
OverrideComponent="true"
|
||||
OverrideController="false"
|
||||
OverrideInclude="Multiplayer/Components/NetworkHitVolumesComponent.h"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<ComponentRelation Constraint="Weak" HasController="false" Name="TransformComponent" Namespace="AzFramework" Include="AzFramework/Components/TransformComponent.h" />
|
||||
</Component>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<Component
|
||||
Name="NetworkRigidBodyComponent"
|
||||
Namespace="Multiplayer"
|
||||
OverrideComponent="true"
|
||||
OverrideController="true"
|
||||
OverrideInclude="Multiplayer/Components/NetworkRigidBodyComponent.h"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<ComponentRelation Constraint="Required" HasController="true" Name="NetworkTransformComponent" Namespace="Multiplayer" Include="Multiplayer/Components/NetworkTransformComponent.h" />
|
||||
|
||||
<RemoteProcedure Name="SendApplyImpulse" InvokeFrom="Server" HandleOn="Authority" IsPublic="true" IsReliable="true" GenerateEventBindings="false" Description="Applies an impulse">
|
||||
<Param Type="AZ::Vector3" Name="impulse" />
|
||||
<Param Type="AZ::Vector3" Name="worldPoint" />
|
||||
</RemoteProcedure>
|
||||
|
||||
</Component>
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Multiplayer/Components/NetworkHitVolumesComponent.h>
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
#include <AzFramework/Physics/Common/PhysicsTypes.h>
|
||||
#include <AzFramework/Physics/CharacterBus.h>
|
||||
#include <AzFramework/Physics/Character.h>
|
||||
#include <AzFramework/Physics/SystemBus.h>
|
||||
#include <AzFramework/Physics/Material.h>
|
||||
#include <MCore/Source/AzCoreConversions.h>
|
||||
#include <Integration/ActorComponentBus.h>
|
||||
#include <Integration/AnimGraphNetworkingBus.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
AZ_CVAR(bool, bg_DrawArticulatedHitVolumes, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Enables debug draw of articulated hit volumes");
|
||||
AZ_CVAR(float, bg_DrawDebugHitVolumeLifetime, 0.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "The lifetime for hit volume draw-debug shapes");
|
||||
|
||||
AZ_CVAR(float, bg_RewindPositionTolerance, 0.0001f, nullptr, AZ::ConsoleFunctorFlags::Null, "Don't sync the physx entity if the square of delta position is less than this value");
|
||||
AZ_CVAR(float, bg_RewindOrientationTolerance, 0.001f, nullptr, AZ::ConsoleFunctorFlags::Null, "Don't sync the physx entity if the square of delta orientation is less than this value");
|
||||
|
||||
NetworkHitVolumesComponent::AnimatedHitVolume::AnimatedHitVolume
|
||||
(
|
||||
AzNetworking::ConnectionId connectionId,
|
||||
Physics::CharacterRequests* character,
|
||||
const char* hitVolumeName,
|
||||
const Physics::ColliderConfiguration* colliderConfig,
|
||||
const Physics::ShapeConfiguration* shapeConfig,
|
||||
const uint32_t jointIndex
|
||||
)
|
||||
: m_colliderConfig(colliderConfig)
|
||||
, m_shapeConfig(shapeConfig)
|
||||
, m_jointIndex(jointIndex)
|
||||
{
|
||||
m_transform.SetOwningConnectionId(connectionId);
|
||||
|
||||
m_colliderOffSetTransform = AZ::Transform::CreateFromQuaternionAndTranslation(m_colliderConfig->m_rotation, m_colliderConfig->m_position);
|
||||
|
||||
if (m_colliderConfig->m_isExclusive)
|
||||
{
|
||||
Physics::SystemRequestBus::BroadcastResult(m_physicsShape, &Physics::SystemRequests::CreateShape, *m_colliderConfig, *m_shapeConfig);
|
||||
}
|
||||
else
|
||||
{
|
||||
Physics::ColliderConfiguration colliderConfiguration = *m_colliderConfig;
|
||||
colliderConfiguration.m_isExclusive = true;
|
||||
colliderConfiguration.m_isSimulated = false;
|
||||
colliderConfiguration.m_isInSceneQueries = true;
|
||||
Physics::SystemRequestBus::BroadcastResult(m_physicsShape, &Physics::SystemRequests::CreateShape, colliderConfiguration, *m_shapeConfig);
|
||||
}
|
||||
|
||||
if (m_physicsShape)
|
||||
{
|
||||
m_physicsShape->SetName(hitVolumeName);
|
||||
character->GetCharacter()->AttachShape(m_physicsShape);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkHitVolumesComponent::AnimatedHitVolume::UpdateTransform(const AZ::Transform& transform)
|
||||
{
|
||||
m_transform = transform;
|
||||
m_physicsShape->SetLocalPose(transform.GetTranslation(), transform.GetRotation());
|
||||
}
|
||||
|
||||
void NetworkHitVolumesComponent::AnimatedHitVolume::SyncToCurrentTransform()
|
||||
{
|
||||
AZ::Transform rewoundTransform;
|
||||
const AZ::Transform& targetTransform = m_transform.Get();
|
||||
const float blendFactor = Multiplayer::GetNetworkTime()->GetHostBlendFactor();
|
||||
if (blendFactor < 1.f)
|
||||
{
|
||||
// If a blend factor was supplied, interpolate the transform appropriately
|
||||
const AZ::Transform& previousTransform = m_transform.GetPrevious();
|
||||
rewoundTransform.SetRotation(previousTransform.GetRotation().Slerp(targetTransform.GetRotation(), blendFactor));
|
||||
rewoundTransform.SetTranslation(previousTransform.GetTranslation().Lerp(targetTransform.GetTranslation(), blendFactor));
|
||||
rewoundTransform.SetUniformScale(AZ::Lerp(previousTransform.GetUniformScale(), targetTransform.GetUniformScale(), blendFactor));
|
||||
}
|
||||
else
|
||||
{
|
||||
rewoundTransform = m_transform.Get();
|
||||
}
|
||||
|
||||
const AZ::Transform physicsTransform = AZ::Transform::CreateFromQuaternionAndTranslation(m_physicsShape->GetLocalPose().second, m_physicsShape->GetLocalPose().first);
|
||||
|
||||
// Don't call SetLocalPose unless the transforms are actually different
|
||||
const AZ::Vector3 positionDelta = physicsTransform.GetTranslation() - rewoundTransform.GetTranslation();
|
||||
const AZ::Quaternion orientationDelta = physicsTransform.GetRotation() - rewoundTransform.GetRotation();
|
||||
|
||||
if ((positionDelta.GetLengthSq() >= bg_RewindPositionTolerance) || (orientationDelta.GetLengthSq() >= bg_RewindOrientationTolerance))
|
||||
{
|
||||
m_physicsShape->SetLocalPose(rewoundTransform.GetTranslation(), rewoundTransform.GetRotation());
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkHitVolumesComponent::NetworkHitVolumesComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serializeContext)
|
||||
{
|
||||
serializeContext->Class<NetworkHitVolumesComponent, NetworkHitVolumesComponentBase>()
|
||||
->Version(1);
|
||||
}
|
||||
NetworkHitVolumesComponentBase::Reflect(context);
|
||||
}
|
||||
|
||||
NetworkHitVolumesComponent::NetworkHitVolumesComponent()
|
||||
: m_syncRewindHandler([this]() { OnSyncRewind(); })
|
||||
, m_preRenderHandler([this](float deltaTime, float blendFactor) { OnPreRender(deltaTime, blendFactor); })
|
||||
, m_transformChangedHandler([this](const AZ::Transform&, const AZ::Transform& worldTm) { OnTransformUpdate(worldTm); })
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void NetworkHitVolumesComponent::OnInit()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void NetworkHitVolumesComponent::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
|
||||
{
|
||||
EMotionFX::Integration::ActorComponentNotificationBus::Handler::BusConnect(GetEntityId());
|
||||
GetNetBindComponent()->AddEntitySyncRewindEventHandler(m_syncRewindHandler);
|
||||
m_physicsCharacter = Physics::CharacterRequestBus::FindFirstHandler(GetEntityId());
|
||||
GetTransformComponent()->BindTransformChangedEventHandler(m_transformChangedHandler);
|
||||
OnTransformUpdate(GetTransformComponent()->GetWorldTM());
|
||||
}
|
||||
|
||||
void NetworkHitVolumesComponent::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
|
||||
{
|
||||
DestroyHitVolumes();
|
||||
EMotionFX::Integration::ActorComponentNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void NetworkHitVolumesComponent::OnPreRender([[maybe_unused]] float deltaTime, [[maybe_unused]] float blendFactor)
|
||||
{
|
||||
if (m_animatedHitVolumes.size() <= 0)
|
||||
{
|
||||
CreateHitVolumes();
|
||||
}
|
||||
|
||||
AZ::Vector3 position, scale;
|
||||
AZ::Quaternion rotation;
|
||||
for (AnimatedHitVolume& hitVolume : m_animatedHitVolumes)
|
||||
{
|
||||
m_actorComponent->GetJointTransformComponents(hitVolume.m_jointIndex, EMotionFX::Integration::Space::ModelSpace, position, rotation, scale);
|
||||
hitVolume.UpdateTransform(AZ::Transform::CreateFromQuaternionAndTranslation(rotation, position) * hitVolume.m_colliderOffSetTransform);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkHitVolumesComponent::OnTransformUpdate([[maybe_unused]] const AZ::Transform& transform)
|
||||
{
|
||||
OnSyncRewind();
|
||||
}
|
||||
|
||||
void NetworkHitVolumesComponent::OnSyncRewind()
|
||||
{
|
||||
if (m_physicsCharacter && m_physicsCharacter->GetCharacter())
|
||||
{
|
||||
uint32_t frameId = static_cast<uint32_t>(Multiplayer::GetNetworkTime()->GetHostFrameId());
|
||||
m_physicsCharacter->GetCharacter()->SetFrameId(frameId);
|
||||
}
|
||||
|
||||
for (AnimatedHitVolume& hitVolume : m_animatedHitVolumes)
|
||||
{
|
||||
hitVolume.SyncToCurrentTransform();
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkHitVolumesComponent::CreateHitVolumes()
|
||||
{
|
||||
if (m_physicsCharacter == nullptr || m_actorComponent == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const Physics::AnimationConfiguration* physicsConfig = m_actorComponent->GetPhysicsConfig();
|
||||
if (physicsConfig == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_hitDetectionConfig = &physicsConfig->m_hitDetectionConfig;
|
||||
const AzNetworking::ConnectionId owningConnectionId = GetNetBindComponent()->GetOwningConnectionId();
|
||||
|
||||
m_animatedHitVolumes.reserve(m_hitDetectionConfig->m_nodes.size());
|
||||
for (const Physics::CharacterColliderNodeConfiguration& nodeConfig : m_hitDetectionConfig->m_nodes)
|
||||
{
|
||||
const AZStd::size_t jointIndex = m_actorComponent->GetJointIndexByName(nodeConfig.m_name.c_str());
|
||||
if (jointIndex == EMotionFX::Integration::ActorComponentRequests::s_invalidJointIndex)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const AzPhysics::ShapeColliderPair& coliderPair : nodeConfig.m_shapes)
|
||||
{
|
||||
const Physics::ColliderConfiguration* colliderConfig = coliderPair.first.get();
|
||||
Physics::ShapeConfiguration* shapeConfig = coliderPair.second.get();
|
||||
m_animatedHitVolumes.emplace_back(owningConnectionId, m_physicsCharacter, nodeConfig.m_name.c_str(), colliderConfig, shapeConfig, aznumeric_cast<uint32_t>(jointIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkHitVolumesComponent::DestroyHitVolumes()
|
||||
{
|
||||
m_animatedHitVolumes.clear();
|
||||
}
|
||||
|
||||
void NetworkHitVolumesComponent::OnActorInstanceCreated([[maybe_unused]] EMotionFX::ActorInstance* actorInstance)
|
||||
{
|
||||
m_actorComponent = EMotionFX::Integration::ActorComponentRequestBus::FindFirstHandler(GetEntity()->GetId());
|
||||
}
|
||||
|
||||
void NetworkHitVolumesComponent::OnActorInstanceDestroyed([[maybe_unused]] EMotionFX::ActorInstance* actorInstance)
|
||||
{
|
||||
m_actorComponent = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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 <Multiplayer/Components/NetworkRigidBodyComponent.h>
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
#include <AzFramework/Physics/RigidBodyBus.h>
|
||||
#include <AzFramework/Physics/SimulatedBodies/RigidBody.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
AZ_CVAR_EXTERNED(float, bg_RewindPositionTolerance);
|
||||
AZ_CVAR_EXTERNED(float, bg_RewindOrientationTolerance);
|
||||
|
||||
void NetworkRigidBodyComponent::NetworkRigidBodyComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serializeContext)
|
||||
{
|
||||
serializeContext->Class<NetworkRigidBodyComponent, NetworkRigidBodyComponentBase>()->Version(1);
|
||||
}
|
||||
NetworkRigidBodyComponentBase::Reflect(context);
|
||||
}
|
||||
|
||||
void NetworkRigidBodyComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC_CE("NetworkRigidBodyService"));
|
||||
}
|
||||
|
||||
void NetworkRigidBodyComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
{
|
||||
required.push_back(AZ_CRC_CE("PhysXRigidBodyService"));
|
||||
}
|
||||
|
||||
void NetworkRigidBodyComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
|
||||
{
|
||||
dependent.push_back(AZ_CRC_CE("TransformService"));
|
||||
dependent.push_back(AZ_CRC_CE("PhysXRigidBodyService"));
|
||||
}
|
||||
|
||||
NetworkRigidBodyComponent::NetworkRigidBodyComponent()
|
||||
: m_syncRewindHandler([this](){ OnSyncRewind(); })
|
||||
, m_transformChangedHandler([this]([[maybe_unused]] const AZ::Transform& localTm, const AZ::Transform& worldTm){ OnTransformUpdate(worldTm); })
|
||||
{
|
||||
}
|
||||
|
||||
void NetworkRigidBodyComponent::OnInit()
|
||||
{
|
||||
}
|
||||
|
||||
void NetworkRigidBodyComponent::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
|
||||
{
|
||||
NetworkRigidBodyRequestBus::Handler::BusConnect(GetEntityId());
|
||||
|
||||
GetNetBindComponent()->AddEntitySyncRewindEventHandler(m_syncRewindHandler);
|
||||
GetEntity()->FindComponent<AzFramework::TransformComponent>()->BindTransformChangedEventHandler(m_transformChangedHandler);
|
||||
|
||||
m_physicsRigidBodyComponent =
|
||||
Physics::RigidBodyRequestBus::FindFirstHandler(GetEntity()->GetId());
|
||||
AZ_Assert(m_physicsRigidBodyComponent, "PhysX Rigid Body Component is required on entity %s", GetEntity()->GetName().c_str());
|
||||
|
||||
if (!HasController())
|
||||
{
|
||||
m_physicsRigidBodyComponent->SetKinematic(true);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkRigidBodyComponent::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
|
||||
{
|
||||
NetworkRigidBodyRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void NetworkRigidBodyComponent::OnTransformUpdate(const AZ::Transform& worldTm)
|
||||
{
|
||||
m_transform = worldTm;
|
||||
|
||||
if (!HasController())
|
||||
{
|
||||
m_physicsRigidBodyComponent->SetKinematicTarget(worldTm);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkRigidBodyComponent::OnSyncRewind()
|
||||
{
|
||||
uint32_t frameId = static_cast<uint32_t>(Multiplayer::GetNetworkTime()->GetHostFrameId());
|
||||
|
||||
AzPhysics::RigidBody* rigidBody = m_physicsRigidBodyComponent->GetRigidBody();
|
||||
rigidBody->SetFrameId(frameId);
|
||||
|
||||
AZ::Transform rewoundTransform;
|
||||
const AZ::Transform& targetTransform = m_transform.Get();
|
||||
const float blendFactor = Multiplayer::GetNetworkTime()->GetHostBlendFactor();
|
||||
if (blendFactor < 1.f)
|
||||
{
|
||||
// If a blend factor was supplied, interpolate the transform appropriately
|
||||
const AZ::Transform& previousTransform = m_transform.GetPrevious();
|
||||
rewoundTransform.SetRotation(previousTransform.GetRotation().Slerp(targetTransform.GetRotation(), blendFactor));
|
||||
rewoundTransform.SetTranslation(previousTransform.GetTranslation().Lerp(targetTransform.GetTranslation(), blendFactor));
|
||||
rewoundTransform.SetUniformScale(AZ::Lerp(previousTransform.GetUniformScale(), targetTransform.GetUniformScale(), blendFactor));
|
||||
}
|
||||
else
|
||||
{
|
||||
rewoundTransform = m_transform.Get();
|
||||
}
|
||||
const AZ::Transform& physicsTransform = rigidBody->GetTransform();
|
||||
|
||||
// Don't call SetLocalPose unless the transforms are actually different
|
||||
const AZ::Vector3 positionDelta = physicsTransform.GetTranslation() - rewoundTransform.GetTranslation();
|
||||
const AZ::Quaternion orientationDelta = physicsTransform.GetRotation() - rewoundTransform.GetRotation();
|
||||
|
||||
if ((positionDelta.GetLengthSq() >= bg_RewindPositionTolerance) ||
|
||||
(orientationDelta.GetLengthSq() >= bg_RewindOrientationTolerance))
|
||||
{
|
||||
rigidBody->SetTransform(rewoundTransform);
|
||||
}
|
||||
}
|
||||
|
||||
NetworkRigidBodyComponentController::NetworkRigidBodyComponentController(NetworkRigidBodyComponent& parent)
|
||||
: NetworkRigidBodyComponentControllerBase(parent)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void NetworkRigidBodyComponentController::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void NetworkRigidBodyComponentController::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void NetworkRigidBodyComponentController::HandleSendApplyImpulse
|
||||
(
|
||||
[[maybe_unused]] AzNetworking::IConnection* invokingConnection,
|
||||
const AZ::Vector3& impulse,
|
||||
const AZ::Vector3& worldPoint
|
||||
)
|
||||
{
|
||||
AzPhysics::RigidBody* rigidBody = GetParent().m_physicsRigidBodyComponent->GetRigidBody();
|
||||
rigidBody->ApplyLinearImpulseAtWorldPoint(impulse, worldPoint);
|
||||
}
|
||||
} // namespace Multiplayer
|
||||
@@ -18,6 +18,8 @@ set(FILES
|
||||
Include/Multiplayer/Components/MultiplayerController.h
|
||||
Include/Multiplayer/Components/MultiplayerComponentRegistry.h
|
||||
Include/Multiplayer/Components/NetBindComponent.h
|
||||
Include/Multiplayer/Components/NetworkHitVolumesComponent.h
|
||||
Include/Multiplayer/Components/NetworkRigidBodyComponent.h
|
||||
Include/Multiplayer/Components/NetworkTransformComponent.h
|
||||
Include/Multiplayer/ConnectionData/IConnectionData.h
|
||||
Include/Multiplayer/EntityDomains/IEntityDomain.h
|
||||
@@ -51,12 +53,16 @@ set(FILES
|
||||
Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml
|
||||
Source/AutoGen/Multiplayer.AutoPackets.xml
|
||||
Source/AutoGen/MultiplayerEditor.AutoPackets.xml
|
||||
Source/AutoGen/NetworkHitVolumesComponent.AutoComponent.xml
|
||||
Source/AutoGen/NetworkRigidBodyComponent.AutoComponent.xml
|
||||
Source/AutoGen/NetworkTransformComponent.AutoComponent.xml
|
||||
Source/Components/LocalPredictionPlayerInputComponent.cpp
|
||||
Source/Components/MultiplayerComponent.cpp
|
||||
Source/Components/MultiplayerController.cpp
|
||||
Source/Components/MultiplayerComponentRegistry.cpp
|
||||
Source/Components/NetBindComponent.cpp
|
||||
Source/Components/NetworkHitVolumesComponent.cpp
|
||||
Source/Components/NetworkRigidBodyComponent.cpp
|
||||
Source/Components/NetworkTransformComponent.cpp
|
||||
Source/ConnectionData/ClientToServerConnectionData.cpp
|
||||
Source/ConnectionData/ClientToServerConnectionData.h
|
||||
|
||||
Reference in New Issue
Block a user