Moved NetworkCharacterComponent out of MPSample and into MP gem
Signed-off-by: Gene Walters <genewalt@amazon.com>
This commit is contained in:
@@ -27,6 +27,7 @@ ly_add_target(
|
||||
AZ::AzNetworking
|
||||
PRIVATE
|
||||
Gem::EMotionFXStaticLib
|
||||
Gem::PhysX.Static
|
||||
AUTOGEN_RULES
|
||||
*.AutoPackets.xml,AutoPackets_Header.jinja,$path/$fileprefix.AutoPackets.h
|
||||
*.AutoPackets.xml,AutoPackets_Inline.jinja,$path/$fileprefix.AutoPackets.inl
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Source/AutoGen/NetworkCharacterComponent.AutoComponent.h>
|
||||
#include <PhysX/CharacterGameplayBus.h>
|
||||
|
||||
namespace Physics
|
||||
{
|
||||
class Character;
|
||||
}
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
class NetworkCharacterComponent
|
||||
: public NetworkCharacterComponentBase
|
||||
, private PhysX::CharacterGameplayRequestBus::Handler
|
||||
{
|
||||
friend class NetworkCharacterComponentController;
|
||||
|
||||
public:
|
||||
AZ_MULTIPLAYER_COMPONENT(Multiplayer::NetworkCharacterComponent, s_networkCharacterComponentConcreteUuid, Multiplayer::NetworkCharacterComponentBase)
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
NetworkCharacterComponent();
|
||||
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC_CE("NetworkRigidBodyService"));
|
||||
}
|
||||
|
||||
void OnInit() override;
|
||||
void OnActivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
|
||||
void OnDeactivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
|
||||
|
||||
private:
|
||||
void OnTranslationChangedEvent(const AZ::Vector3& translation);
|
||||
void OnSyncRewind();
|
||||
|
||||
// CharacterGameplayRequestBus
|
||||
bool IsOnGround() const override;
|
||||
float GetGravityMultiplier() const override { return {}; }
|
||||
void SetGravityMultiplier([[maybe_unused]] float gravityMultiplier) override {}
|
||||
AZ::Vector3 GetFallingVelocity() const override { return {}; }
|
||||
void SetFallingVelocity([[maybe_unused]] const AZ::Vector3& fallingVelocity) override {}
|
||||
|
||||
Physics::Character* m_physicsCharacter = nullptr;
|
||||
Multiplayer::EntitySyncRewindEvent::Handler m_syncRewindHandler = Multiplayer::EntitySyncRewindEvent::Handler([this]() { OnSyncRewind(); });
|
||||
AZ::Event<AZ::Vector3>::Handler m_translationEventHandler;
|
||||
};
|
||||
|
||||
class NetworkCharacterComponentController
|
||||
: public NetworkCharacterComponentControllerBase
|
||||
{
|
||||
public:
|
||||
NetworkCharacterComponentController(NetworkCharacterComponent& parent);
|
||||
|
||||
void OnActivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
|
||||
void OnDeactivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
|
||||
|
||||
AZ::Vector3 TryMoveWithVelocity(const AZ::Vector3& velocity, float deltaTime);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<Component
|
||||
Name="NetworkCharacterComponent"
|
||||
Namespace="Multiplayer"
|
||||
OverrideComponent="true"
|
||||
OverrideController="true"
|
||||
OverrideInclude="Multiplayer/Components/NetworkCharacterComponent.h"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<ComponentRelation Constraint="Required" HasController="true" Name="NetworkTransformComponent" Namespace="Multiplayer" Include="Multiplayer/Components/NetworkTransformComponent.h" />
|
||||
</Component>
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Multiplayer/Components/NetworkCharacterComponent.h>
|
||||
#include <Multiplayer/Components/NetworkRigidBodyComponent.h>
|
||||
#include <AzFramework/Visibility/EntityBoundsUnionBus.h>
|
||||
#include <AzFramework/Physics/CharacterBus.h>
|
||||
#include <AzFramework/Physics/Character.h>
|
||||
#include <Multiplayer/Components/NetworkTransformComponent.h>
|
||||
#include <Multiplayer/NetworkTime/INetworkTime.h>
|
||||
#include <PhysXCharacters/API/CharacterController.h>
|
||||
#include <PhysX/PhysXLocks.h>
|
||||
#include <PhysX/Utils.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
|
||||
bool CollisionLayerBasedControllerFilter(const physx::PxController& controllerA, const physx::PxController& controllerB)
|
||||
{
|
||||
PHYSX_SCENE_READ_LOCK(controllerA.getActor()->getScene());
|
||||
physx::PxRigidDynamic* actorA = controllerA.getActor();
|
||||
physx::PxRigidDynamic* actorB = controllerB.getActor();
|
||||
|
||||
if (actorA && actorA->getNbShapes() > 0 && actorB && actorB->getNbShapes() > 0)
|
||||
{
|
||||
physx::PxShape* shapeA = nullptr;
|
||||
actorA->getShapes(&shapeA, 1, 0);
|
||||
physx::PxFilterData filterDataA = shapeA->getSimulationFilterData();
|
||||
physx::PxShape* shapeB = nullptr;
|
||||
actorB->getShapes(&shapeB, 1, 0);
|
||||
physx::PxFilterData filterDataB = shapeB->getSimulationFilterData();
|
||||
return PhysX::Utils::Collision::ShouldCollide(filterDataA, filterDataB);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
physx::PxQueryHitType::Enum CollisionLayerBasedObjectPreFilter(
|
||||
const physx::PxFilterData& filterData,
|
||||
const physx::PxShape* shape,
|
||||
const physx::PxRigidActor* actor,
|
||||
[[maybe_unused]] physx::PxHitFlags& queryFlags)
|
||||
{
|
||||
// non-kinematic dynamic bodies should not impede the movement of the character
|
||||
if (actor->getConcreteType() == physx::PxConcreteType::eRIGID_DYNAMIC)
|
||||
{
|
||||
const physx::PxRigidDynamic* rigidDynamic = static_cast<const physx::PxRigidDynamic*>(actor);
|
||||
|
||||
bool isKinematic = (rigidDynamic->getRigidBodyFlags() & physx::PxRigidBodyFlag::eKINEMATIC);
|
||||
if (isKinematic)
|
||||
{
|
||||
const PhysX::ActorData* actorData = PhysX::Utils::GetUserData(rigidDynamic);
|
||||
if (actorData)
|
||||
{
|
||||
const AZ::EntityId entityId = actorData->GetEntityId();
|
||||
|
||||
if (Multiplayer::NetworkRigidBodyRequestBus::FindFirstHandler(entityId) != nullptr)
|
||||
{
|
||||
// Network rigid bodies are kinematic on the client but dynamic on the server,
|
||||
// hence filtering treats these actors as dynamic to support client prediction and avoid desyncs
|
||||
isKinematic = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isKinematic)
|
||||
{
|
||||
return physx::PxQueryHitType::eNONE;
|
||||
}
|
||||
}
|
||||
|
||||
// all other cases should be determined by collision filters
|
||||
if (PhysX::Utils::Collision::ShouldCollide(filterData, shape->getSimulationFilterData()))
|
||||
{
|
||||
return physx::PxQueryHitType::eBLOCK;
|
||||
}
|
||||
|
||||
return physx::PxQueryHitType::eNONE;
|
||||
}
|
||||
|
||||
void NetworkCharacterComponent::NetworkCharacterComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serializeContext)
|
||||
{
|
||||
serializeContext->Class<NetworkCharacterComponent, NetworkCharacterComponentBase>()
|
||||
->Version(1);
|
||||
}
|
||||
NetworkCharacterComponentBase::Reflect(context);
|
||||
}
|
||||
|
||||
NetworkCharacterComponent::NetworkCharacterComponent()
|
||||
: m_translationEventHandler([this](const AZ::Vector3& translation) { OnTranslationChangedEvent(translation); })
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void NetworkCharacterComponent::OnInit()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void NetworkCharacterComponent::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
|
||||
{
|
||||
Physics::CharacterRequests* characterRequests = Physics::CharacterRequestBus::FindFirstHandler(GetEntityId());
|
||||
m_physicsCharacter = (characterRequests != nullptr) ? characterRequests->GetCharacter() : nullptr;
|
||||
GetNetBindComponent()->AddEntitySyncRewindEventHandler(m_syncRewindHandler);
|
||||
|
||||
if (m_physicsCharacter)
|
||||
{
|
||||
auto controller = static_cast<PhysX::CharacterController*>(m_physicsCharacter);
|
||||
controller->SetFilterFlags(physx::PxQueryFlag::eSTATIC | physx::PxQueryFlag::eDYNAMIC | physx::PxQueryFlag::ePREFILTER);
|
||||
if (auto callbackManager = controller->GetCallbackManager())
|
||||
{
|
||||
callbackManager->SetControllerFilter(CollisionLayerBasedControllerFilter);
|
||||
callbackManager->SetObjectPreFilter(CollisionLayerBasedObjectPreFilter);
|
||||
}
|
||||
}
|
||||
|
||||
if (!HasController())
|
||||
{
|
||||
GetNetworkTransformComponent()->TranslationAddEvent(m_translationEventHandler);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkCharacterComponent::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void NetworkCharacterComponent::OnTranslationChangedEvent([[maybe_unused]] const AZ::Vector3& translation)
|
||||
{
|
||||
OnSyncRewind();
|
||||
}
|
||||
|
||||
void NetworkCharacterComponent::OnSyncRewind()
|
||||
{
|
||||
if (m_physicsCharacter == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const AZ::Vector3 currPosition = m_physicsCharacter->GetBasePosition();
|
||||
if (!currPosition.IsClose(GetNetworkTransformComponent()->GetTranslation()))
|
||||
{
|
||||
uint32_t frameId = static_cast<uint32_t>(Multiplayer::GetNetworkTime()->GetHostFrameId());
|
||||
m_physicsCharacter->SetFrameId(frameId);
|
||||
//m_physicsCharacter->SetBasePosition(GetNetworkTransformComponent()->GetTranslation());
|
||||
}
|
||||
}
|
||||
|
||||
bool NetworkCharacterComponent::IsOnGround() const
|
||||
{
|
||||
auto pxController = static_cast<physx::PxController*>(m_physicsCharacter->GetNativePointer());
|
||||
if (!pxController)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
physx::PxControllerState state;
|
||||
pxController->getState(state);
|
||||
return state.touchedActor != nullptr || (state.collisionFlags & physx::PxControllerCollisionFlag::eCOLLISION_DOWN) != 0;
|
||||
}
|
||||
|
||||
NetworkCharacterComponentController::NetworkCharacterComponentController(NetworkCharacterComponent& parent)
|
||||
: NetworkCharacterComponentControllerBase(parent)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void NetworkCharacterComponentController::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void NetworkCharacterComponentController::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
AZ::Vector3 NetworkCharacterComponentController::TryMoveWithVelocity(const AZ::Vector3& velocity, [[maybe_unused]] float deltaTime)
|
||||
{
|
||||
// Ensure any entities that we might interact with are properly synchronized to their rewind state
|
||||
if (IsAuthority())
|
||||
{
|
||||
const AZ::Aabb entityStartBounds = AZ::Interface<AzFramework::IEntityBoundsUnion>::Get()->GetEntityLocalBoundsUnion(GetEntity()->GetId());
|
||||
const AZ::Aabb entityFinalBounds = entityStartBounds.GetTranslated(velocity);
|
||||
AZ::Aabb entitySweptBounds = entityStartBounds;
|
||||
entitySweptBounds.AddAabb(entityFinalBounds);
|
||||
Multiplayer::GetNetworkTime()->SyncEntitiesToRewindState(entitySweptBounds);
|
||||
}
|
||||
|
||||
if ((GetParent().m_physicsCharacter == nullptr) || (velocity.GetLengthSq() <= 0.0f))
|
||||
{
|
||||
return GetEntity()->GetTransform()->GetWorldTranslation();
|
||||
}
|
||||
GetParent().m_physicsCharacter->AddVelocity(velocity);
|
||||
GetParent().m_physicsCharacter->ApplyRequestedVelocity(deltaTime);
|
||||
GetEntity()->GetTransform()->SetWorldTranslation(GetParent().m_physicsCharacter->GetBasePosition());
|
||||
AZLOG
|
||||
(
|
||||
NET_Movement,
|
||||
"Moved to position %f x %f x %f",
|
||||
GetParent().m_physicsCharacter->GetBasePosition().GetX(),
|
||||
GetParent().m_physicsCharacter->GetBasePosition().GetY(),
|
||||
GetParent().m_physicsCharacter->GetBasePosition().GetZ()
|
||||
);
|
||||
return GetEntity()->GetTransform()->GetWorldTranslation();
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ set(FILES
|
||||
Include/Multiplayer/Components/MultiplayerController.h
|
||||
Include/Multiplayer/Components/MultiplayerComponentRegistry.h
|
||||
Include/Multiplayer/Components/NetBindComponent.h
|
||||
Include/Multiplayer/Components/NetworkCharacterComponent.h
|
||||
Include/Multiplayer/Components/NetworkHitVolumesComponent.h
|
||||
Include/Multiplayer/Components/NetworkRigidBodyComponent.h
|
||||
Include/Multiplayer/Components/NetworkTransformComponent.h
|
||||
@@ -53,6 +54,7 @@ set(FILES
|
||||
Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml
|
||||
Source/AutoGen/Multiplayer.AutoPackets.xml
|
||||
Source/AutoGen/MultiplayerEditor.AutoPackets.xml
|
||||
Source/AutoGen/NetworkCharacterComponent.AutoComponent.xml
|
||||
Source/AutoGen/NetworkHitVolumesComponent.AutoComponent.xml
|
||||
Source/AutoGen/NetworkRigidBodyComponent.AutoComponent.xml
|
||||
Source/AutoGen/NetworkTransformComponent.AutoComponent.xml
|
||||
@@ -61,6 +63,7 @@ set(FILES
|
||||
Source/Components/MultiplayerController.cpp
|
||||
Source/Components/MultiplayerComponentRegistry.cpp
|
||||
Source/Components/NetBindComponent.cpp
|
||||
Source/Components/NetworkCharacterComponent.cpp
|
||||
Source/Components/NetworkHitVolumesComponent.cpp
|
||||
Source/Components/NetworkRigidBodyComponent.cpp
|
||||
Source/Components/NetworkTransformComponent.cpp
|
||||
|
||||
Reference in New Issue
Block a user