NetworkCharacterComponent.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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/NetworkCharacterComponent.h>
  9. #include <Multiplayer/Components/NetworkRigidBodyComponent.h>
  10. #include <AzCore/RTTI/BehaviorContext.h>
  11. #include <AzFramework/Visibility/EntityBoundsUnionBus.h>
  12. #include <AzFramework/Physics/CharacterBus.h>
  13. #include <AzFramework/Physics/Character.h>
  14. #include <Multiplayer/Components/NetworkTransformComponent.h>
  15. #include <Multiplayer/NetworkTime/INetworkTime.h>
  16. #include <PhysXCharacters/API/CharacterController.h>
  17. #include <PhysX/PhysXLocks.h>
  18. #include <PhysX/Utils.h>
  19. namespace Multiplayer
  20. {
  21. bool CollisionLayerBasedControllerFilter(const physx::PxController& controllerA, const physx::PxController& controllerB)
  22. {
  23. PHYSX_SCENE_READ_LOCK(controllerA.getActor()->getScene());
  24. physx::PxRigidDynamic* actorA = controllerA.getActor();
  25. physx::PxRigidDynamic* actorB = controllerB.getActor();
  26. if (actorA && actorA->getNbShapes() > 0 && actorB && actorB->getNbShapes() > 0)
  27. {
  28. physx::PxShape* shapeA = nullptr;
  29. actorA->getShapes(&shapeA, 1, 0);
  30. physx::PxFilterData filterDataA = shapeA->getSimulationFilterData();
  31. physx::PxShape* shapeB = nullptr;
  32. actorB->getShapes(&shapeB, 1, 0);
  33. physx::PxFilterData filterDataB = shapeB->getSimulationFilterData();
  34. return PhysX::Utils::Collision::ShouldCollide(filterDataA, filterDataB);
  35. }
  36. return true;
  37. }
  38. physx::PxQueryHitType::Enum CollisionLayerBasedObjectPreFilter(
  39. const physx::PxFilterData& filterData,
  40. const physx::PxShape* shape,
  41. const physx::PxRigidActor* actor,
  42. [[maybe_unused]] physx::PxHitFlags& queryFlags)
  43. {
  44. // non-kinematic dynamic bodies should not impede the movement of the character
  45. if (actor->getConcreteType() == physx::PxConcreteType::eRIGID_DYNAMIC)
  46. {
  47. const physx::PxRigidDynamic* rigidDynamic = static_cast<const physx::PxRigidDynamic*>(actor);
  48. bool isKinematic = (rigidDynamic->getRigidBodyFlags() & physx::PxRigidBodyFlag::eKINEMATIC);
  49. if (isKinematic)
  50. {
  51. const PhysX::ActorData* actorData = PhysX::Utils::GetUserData(rigidDynamic);
  52. if (actorData)
  53. {
  54. const AZ::EntityId entityId = actorData->GetEntityId();
  55. if (Multiplayer::NetworkRigidBodyRequestBus::FindFirstHandler(entityId) != nullptr)
  56. {
  57. // Network rigid bodies are kinematic on the client but dynamic on the server,
  58. // hence filtering treats these actors as dynamic to support client prediction and avoid desyncs
  59. isKinematic = false;
  60. }
  61. }
  62. }
  63. if (!isKinematic)
  64. {
  65. return physx::PxQueryHitType::eNONE;
  66. }
  67. }
  68. // all other cases should be determined by collision filters
  69. if (PhysX::Utils::Collision::ShouldCollide(filterData, shape->getSimulationFilterData()))
  70. {
  71. return physx::PxQueryHitType::eBLOCK;
  72. }
  73. return physx::PxQueryHitType::eNONE;
  74. }
  75. void NetworkCharacterComponent::Reflect(AZ::ReflectContext* context)
  76. {
  77. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  78. if (serializeContext)
  79. {
  80. serializeContext->Class<NetworkCharacterComponent, NetworkCharacterComponentBase>()
  81. ->Version(1);
  82. }
  83. NetworkCharacterComponentBase::Reflect(context);
  84. NetworkCharacterComponentController::Reflect(context);
  85. }
  86. void NetworkCharacterComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  87. {
  88. NetworkCharacterComponentBase::GetRequiredServices(required);
  89. required.push_back(AZ_CRC_CE("PhysicsCharacterControllerService"));
  90. }
  91. NetworkCharacterComponent::NetworkCharacterComponent()
  92. : m_translationEventHandler([this](const AZ::Vector3& translation) { OnTranslationChangedEvent(translation); })
  93. {
  94. }
  95. void NetworkCharacterComponent::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  96. {
  97. // During activation the character controller is not created yet.
  98. // Connect to CharacterNotificationBus to listen when it's activated after creation.
  99. Physics::CharacterNotificationBus::Handler::BusConnect(GetEntityId());
  100. // Set up the network event handlers. These can be bound before the character controller is created
  101. // because they check for the character controller to exist inside of the handlers.
  102. GetNetBindComponent()->AddEntitySyncRewindEventHandler(m_syncRewindHandler);
  103. if (!HasController())
  104. {
  105. GetNetworkTransformComponent()->TranslationAddEvent(m_translationEventHandler);
  106. }
  107. }
  108. void NetworkCharacterComponent::OnCharacterActivated(const AZ::EntityId& entityId)
  109. {
  110. Physics::CharacterRequests* characterRequests = Physics::CharacterRequestBus::FindFirstHandler(entityId);
  111. AZ_Assert(characterRequests, "Character Controller component is required on entity %s", GetEntity()->GetName().c_str());
  112. m_physicsCharacter = characterRequests->GetCharacter();
  113. if (m_physicsCharacter)
  114. {
  115. auto controller = static_cast<PhysX::CharacterController*>(m_physicsCharacter);
  116. controller->SetFilterFlags(physx::PxQueryFlag::eSTATIC | physx::PxQueryFlag::eDYNAMIC | physx::PxQueryFlag::ePREFILTER);
  117. if (auto callbackManager = controller->GetCallbackManager())
  118. {
  119. callbackManager->SetControllerFilter(CollisionLayerBasedControllerFilter);
  120. callbackManager->SetObjectPreFilter(CollisionLayerBasedObjectPreFilter);
  121. }
  122. }
  123. }
  124. void NetworkCharacterComponent::OnCharacterDeactivated([[maybe_unused]] const AZ::EntityId& entityId)
  125. {
  126. m_physicsCharacter = nullptr;
  127. }
  128. void NetworkCharacterComponent::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  129. {
  130. Physics::CharacterNotificationBus::Handler::BusDisconnect();
  131. m_syncRewindHandler.Disconnect();
  132. m_translationEventHandler.Disconnect();
  133. m_physicsCharacter = nullptr;
  134. }
  135. void NetworkCharacterComponent::OnTranslationChangedEvent([[maybe_unused]] const AZ::Vector3& translation)
  136. {
  137. OnSyncRewind();
  138. }
  139. void NetworkCharacterComponent::OnSyncRewind()
  140. {
  141. if (m_physicsCharacter == nullptr)
  142. {
  143. return;
  144. }
  145. const AZ::Vector3 currPosition = m_physicsCharacter->GetBasePosition();
  146. if (!currPosition.IsClose(GetNetworkTransformComponent()->GetTranslation()))
  147. {
  148. uint32_t frameId = static_cast<uint32_t>(Multiplayer::GetNetworkTime()->GetHostFrameId());
  149. m_physicsCharacter->SetFrameId(frameId);
  150. //m_physicsCharacter->SetBasePosition(GetNetworkTransformComponent()->GetTranslation());
  151. }
  152. }
  153. void NetworkCharacterComponentController::Reflect(AZ::ReflectContext* context)
  154. {
  155. if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
  156. {
  157. behaviorContext->EBus<NetworkCharacterRequestBus>("NetworkCharacterRequestBus")
  158. ->Event("TryMoveWithVelocity", &NetworkCharacterRequestBus::Events::TryMoveWithVelocity, {{ { "Velocity" }, { "DeltaTime" } }});
  159. behaviorContext->Class<NetworkCharacterComponentController>("NetworkCharacterComponentController")
  160. ->RequestBus("NetworkCharacterRequestBus");
  161. }
  162. }
  163. NetworkCharacterComponentController::NetworkCharacterComponentController(NetworkCharacterComponent& parent)
  164. : NetworkCharacterComponentControllerBase(parent)
  165. {
  166. ;
  167. }
  168. void NetworkCharacterComponentController::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  169. {
  170. NetworkCharacterRequestBus::Handler::BusConnect(GetEntity()->GetId());
  171. }
  172. void NetworkCharacterComponentController::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  173. {
  174. NetworkCharacterRequestBus::Handler::BusDisconnect(GetEntity()->GetId());
  175. }
  176. AZ::Vector3 NetworkCharacterComponentController::TryMoveWithVelocity(const AZ::Vector3& velocity, [[maybe_unused]] float deltaTime)
  177. {
  178. // Ensure any entities that we might interact with are properly synchronized to their rewind state
  179. if (IsNetEntityRoleAuthority())
  180. {
  181. const AZ::Aabb entityStartBounds = AZ::Interface<AzFramework::IEntityBoundsUnion>::Get()->GetEntityWorldBoundsUnion(GetEntity()->GetId());
  182. const AZ::Aabb entityFinalBounds = entityStartBounds.GetTranslated(velocity);
  183. AZ::Aabb entitySweptBounds = entityStartBounds;
  184. entitySweptBounds.AddAabb(entityFinalBounds);
  185. Multiplayer::GetNetworkTime()->SyncEntitiesToRewindState(entitySweptBounds);
  186. }
  187. if (GetParent().m_physicsCharacter != nullptr)
  188. {
  189. GetParent().m_physicsCharacter->SetRotation(GetEntity()->GetTransform()->GetWorldRotationQuaternion());
  190. if (velocity.GetLengthSq() > 0.0f)
  191. {
  192. GetParent().m_physicsCharacter->Move(velocity * deltaTime, deltaTime);
  193. GetEntity()->GetTransform()->SetWorldTM(GetParent().m_physicsCharacter->GetTransform());
  194. AZLOG(
  195. NET_Movement,
  196. "Moved to position %f x %f x %f",
  197. GetParent().m_physicsCharacter->GetBasePosition().GetX(),
  198. GetParent().m_physicsCharacter->GetBasePosition().GetY(),
  199. GetParent().m_physicsCharacter->GetBasePosition().GetZ());
  200. }
  201. }
  202. return GetEntity()->GetTransform()->GetWorldTranslation();
  203. }
  204. }