NetworkRigidBodyComponent.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <Multiplayer/Components/NetworkRigidBodyComponent.h>
  9. #include <AzFramework/Components/TransformComponent.h>
  10. #include <AzFramework/Physics/RigidBodyBus.h>
  11. #include <AzFramework/Physics/SimulatedBodies/RigidBody.h>
  12. namespace Multiplayer
  13. {
  14. AZ_CVAR_EXTERNED(float, bg_RewindPositionTolerance);
  15. AZ_CVAR_EXTERNED(float, bg_RewindOrientationTolerance);
  16. void NetworkRigidBodyComponent::NetworkRigidBodyComponent::Reflect(AZ::ReflectContext* context)
  17. {
  18. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  19. if (serializeContext)
  20. {
  21. serializeContext->Class<NetworkRigidBodyComponent, NetworkRigidBodyComponentBase>()->Version(1);
  22. }
  23. NetworkRigidBodyComponentBase::Reflect(context);
  24. }
  25. void NetworkRigidBodyComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  26. {
  27. NetworkRigidBodyComponentBase::GetRequiredServices(required);
  28. required.push_back(AZ_CRC_CE("PhysicsDynamicRigidBodyService"));
  29. }
  30. NetworkRigidBodyComponent::NetworkRigidBodyComponent()
  31. : m_syncRewindHandler([this](){ OnSyncRewind(); })
  32. , m_transformChangedHandler([this]([[maybe_unused]] const AZ::Transform& localTm, const AZ::Transform& worldTm){ OnTransformUpdate(worldTm); })
  33. {
  34. }
  35. void NetworkRigidBodyComponent::OnInit()
  36. {
  37. }
  38. void NetworkRigidBodyComponent::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  39. {
  40. // During activation the simulated bodies are not created yet.
  41. // Connect to RigidBodyNotificationBus to listen when it's enabled after creation.
  42. Physics::RigidBodyNotificationBus::Handler::BusConnect(GetEntityId());
  43. }
  44. void NetworkRigidBodyComponent::OnPhysicsEnabled(const AZ::EntityId& entityId)
  45. {
  46. Physics::RigidBodyNotificationBus::Handler::BusDisconnect();
  47. m_physicsRigidBodyComponent = Physics::RigidBodyRequestBus::FindFirstHandler(entityId);
  48. AZ_Assert(m_physicsRigidBodyComponent, "Physics Rigid Body is required on entity %s", GetEntity()->GetName().c_str());
  49. // By default we're kinematic unless there is a controller, in which case the controller will handle it.
  50. if (!HasController())
  51. {
  52. m_physicsRigidBodyComponent->SetKinematic(true);
  53. }
  54. NetworkRigidBodyRequestBus::Handler::BusConnect(GetEntityId());
  55. GetNetBindComponent()->AddEntitySyncRewindEventHandler(m_syncRewindHandler);
  56. GetEntity()->GetTransform()->BindTransformChangedEventHandler(m_transformChangedHandler);
  57. }
  58. void NetworkRigidBodyComponent::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  59. {
  60. Physics::RigidBodyNotificationBus::Handler::BusDisconnect();
  61. NetworkRigidBodyRequestBus::Handler::BusDisconnect();
  62. m_physicsRigidBodyComponent = nullptr;
  63. }
  64. void NetworkRigidBodyComponent::OnTransformUpdate(const AZ::Transform& worldTm)
  65. {
  66. m_transform = worldTm;
  67. if (!HasController())
  68. {
  69. m_physicsRigidBodyComponent->SetKinematicTarget(worldTm);
  70. }
  71. }
  72. void NetworkRigidBodyComponent::OnSyncRewind()
  73. {
  74. uint32_t frameId = static_cast<uint32_t>(Multiplayer::GetNetworkTime()->GetHostFrameId());
  75. if (AzPhysics::RigidBody* rigidBody = m_physicsRigidBodyComponent->GetRigidBody())
  76. {
  77. rigidBody->SetFrameId(frameId);
  78. AZ::Transform rewoundTransform;
  79. const AZ::Transform& targetTransform = m_transform.Get();
  80. const float blendFactor = Multiplayer::GetNetworkTime()->GetHostBlendFactor();
  81. if (blendFactor < 1.f)
  82. {
  83. // If a blend factor was supplied, interpolate the transform appropriately
  84. const AZ::Transform& previousTransform = m_transform.GetPrevious();
  85. rewoundTransform.SetRotation(previousTransform.GetRotation().Slerp(targetTransform.GetRotation(), blendFactor));
  86. rewoundTransform.SetTranslation(previousTransform.GetTranslation().Lerp(targetTransform.GetTranslation(), blendFactor));
  87. rewoundTransform.SetUniformScale(AZ::Lerp(previousTransform.GetUniformScale(), targetTransform.GetUniformScale(), blendFactor));
  88. }
  89. else
  90. {
  91. rewoundTransform = m_transform.Get();
  92. }
  93. const AZ::Transform& physicsTransform = rigidBody->GetTransform();
  94. // Don't call SetLocalPose unless the transforms are actually different
  95. const AZ::Vector3 positionDelta = physicsTransform.GetTranslation() - rewoundTransform.GetTranslation();
  96. const AZ::Quaternion orientationDelta = physicsTransform.GetRotation() - rewoundTransform.GetRotation();
  97. if ((positionDelta.GetLengthSq() >= bg_RewindPositionTolerance) ||
  98. (orientationDelta.GetLengthSq() >= bg_RewindOrientationTolerance))
  99. {
  100. rigidBody->SetTransform(rewoundTransform);
  101. }
  102. }
  103. }
  104. NetworkRigidBodyComponentController::NetworkRigidBodyComponentController(NetworkRigidBodyComponent& parent)
  105. : NetworkRigidBodyComponentControllerBase(parent)
  106. #if AZ_TRAIT_SERVER
  107. , m_transformChangedHandler([this](const AZ::Transform&, const AZ::Transform&) { OnTransformUpdate(); })
  108. #endif
  109. {
  110. ;
  111. }
  112. void NetworkRigidBodyComponentController::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  113. {
  114. // During activation the simulated bodies are not created yet.
  115. // Connect to RigidBodyNotificationBus to listen when it's enabled after creation.
  116. Physics::RigidBodyNotificationBus::Handler::BusConnect(GetEntityId());
  117. }
  118. void NetworkRigidBodyComponentController::OnPhysicsEnabled(const AZ::EntityId& entityId)
  119. {
  120. Physics::RigidBodyNotificationBus::Handler::BusDisconnect();
  121. m_physicsRigidBodyComponent = Physics::RigidBodyRequestBus::FindFirstHandler(entityId);
  122. AZ_Assert(m_physicsRigidBodyComponent, "Physics Rigid Body is required on entity %s", GetEntity()->GetName().c_str());
  123. m_physicsRigidBodyComponent->SetKinematic(false);
  124. #if AZ_TRAIT_SERVER
  125. if (IsNetEntityRoleAuthority())
  126. {
  127. if (AzPhysics::RigidBody* rigidBody = m_physicsRigidBodyComponent->GetRigidBody())
  128. {
  129. rigidBody->SetLinearVelocity(GetLinearVelocity());
  130. rigidBody->SetAngularVelocity(GetAngularVelocity());
  131. GetEntity()->GetTransform()->BindTransformChangedEventHandler(m_transformChangedHandler);
  132. }
  133. }
  134. #endif
  135. }
  136. void NetworkRigidBodyComponentController::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  137. {
  138. #if AZ_TRAIT_SERVER
  139. m_transformChangedHandler.Disconnect();
  140. #endif
  141. if (m_physicsRigidBodyComponent)
  142. {
  143. m_physicsRigidBodyComponent->SetKinematic(true);
  144. m_physicsRigidBodyComponent = nullptr;
  145. }
  146. }
  147. #if AZ_TRAIT_SERVER
  148. void NetworkRigidBodyComponentController::HandleSendApplyImpulse
  149. (
  150. [[maybe_unused]] AzNetworking::IConnection* invokingConnection,
  151. const AZ::Vector3& impulse,
  152. const AZ::Vector3& worldPoint
  153. )
  154. {
  155. if (AzPhysics::RigidBody* rigidBody = m_physicsRigidBodyComponent->GetRigidBody())
  156. {
  157. rigidBody->ApplyLinearImpulseAtWorldPoint(impulse, worldPoint);
  158. }
  159. }
  160. void NetworkRigidBodyComponentController::OnTransformUpdate()
  161. {
  162. if (AzPhysics::RigidBody* rigidBody = m_physicsRigidBodyComponent->GetRigidBody())
  163. {
  164. SetLinearVelocity(rigidBody->GetLinearVelocity());
  165. SetAngularVelocity(rigidBody->GetAngularVelocity());
  166. }
  167. }
  168. #endif
  169. } // namespace Multiplayer