diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBody.h b/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBody.h index ed8a68dc24..9d45a17edc 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBody.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBody.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,22 @@ namespace AzPhysics return m_customUserData; } + //! Helper functions for setting frame ID. + //! @param frameId Optionally set frame ID for the systems moving the actors back in time. + void SetFrameId(uint32_t frameId) + { + m_frameId = frameId; + } + + //! Helper functions for getting the set frame ID. + //! @return Will return the frame ID. + uint32_t GetFrameId() const + { + return m_frameId; + } + + static constexpr uint32_t UndefinedFrameId = AZStd::numeric_limits::max(); + //! Perform a ray cast on this Simulated Body. //! @param request The request to make. //! @return Returns the closest hit, if any, against this simulated body. @@ -126,6 +143,7 @@ namespace AzPhysics SimulatedBodyEvents::OnTriggerExit m_triggerExitEvent; void* m_customUserData = nullptr; + uint32_t m_frameId = UndefinedFrameId; // helpers for reflecting to behavior context SimulatedBodyEvents::OnCollisionBegin* GetOnCollisionBeginEvent(); diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerTypes.h b/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerTypes.h index 16cc4146dd..85c7e85c0a 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerTypes.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerTypes.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,7 @@ namespace Multiplayer //! This is a strong typedef for representing the number of application frames since application start. AZ_TYPE_SAFE_INTEGRAL(HostFrameId, uint32_t); - static constexpr HostFrameId InvalidHostFrameId = HostFrameId{ 0xFFFFFFFF }; + static constexpr HostFrameId InvalidHostFrameId = HostFrameId{ AzPhysics::SimulatedBody::UndefinedFrameId }; using LongNetworkString = AZ::CVarFixedString; using ReliabilityType = AzNetworking::ReliabilityType; diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Physics/PhysicsUtils.h b/Gems/Multiplayer/Code/Include/Multiplayer/Physics/PhysicsUtils.h new file mode 100644 index 0000000000..4013e20a1e --- /dev/null +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Physics/PhysicsUtils.h @@ -0,0 +1,37 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#pragma once + +#include + +namespace Multiplayer +{ + namespace Physics + { + //! Performs rewind-aware ray cast in the default physics world. + //! @param request The ray cast request to make. + //! @return Returns a structure that contains a list of Hits. + AzPhysics::SceneQueryHits RayCast(const AzPhysics::RayCastRequest& request); + + //! Performs rewind-aware shape cast in the default physics world. + //! @param request The shape cast request to make. + //! @return Returns a structure that contains a list of Hits. + AzPhysics::SceneQueryHits ShapeCast(const AzPhysics::ShapeCastRequest& request); + + //! Performs rewind-aware overlap in the default physics world. + //! @param request The overlap request to make. + //! @return Returns a structure that contains a list of Hits. + AzPhysics::SceneQueryHits Overlap(const AzPhysics::OverlapRequest& request); + + } // namespace Physics +} // namespace Multiplayer diff --git a/Gems/Multiplayer/Code/Source/Physics/PhysicsUtils.cpp b/Gems/Multiplayer/Code/Source/Physics/PhysicsUtils.cpp new file mode 100644 index 0000000000..6341f5b060 --- /dev/null +++ b/Gems/Multiplayer/Code/Source/Physics/PhysicsUtils.cpp @@ -0,0 +1,104 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include + +#include +#include +#include +#include + +namespace +{ + template + AzPhysics::SceneQueryHits SceneQueryInternal(const RequestT& request) + { + auto* sceneInterface = AZ::Interface::Get(); + if (!sceneInterface) + { + return {}; + } + + AzPhysics::SceneHandle sceneHandle = sceneInterface->GetSceneHandle(AzPhysics::DefaultPhysicsSceneName); + if (sceneHandle == AzPhysics::InvalidSceneHandle) + { + return {}; + } + + Multiplayer::INetworkTime* currentNetTime = Multiplayer::GetNetworkTime(); + + if(!currentNetTime->IsTimeRewound()) + { + // If the time is not rewound, we simply execute the scene query as is. + AzPhysics::SceneQueryHits result = sceneInterface->QueryScene(sceneHandle, &request); + return result; + } + + // If the time is rewound, we want to query against rigid bodies present at the same frame ID: the same as the current rewound time is. + RequestT netSceneQueryRequest = request; + netSceneQueryRequest.m_filterCallback = [&request, currentFrameId = (uint32_t)currentNetTime->GetHostFrameId()]( + const AzPhysics::SimulatedBody* body, const ::Physics::Shape* shape) + { + if (body->GetFrameId() == AzPhysics::SimulatedBody::UndefinedFrameId || body->GetFrameId() == currentFrameId) + { + if (request.m_filterCallback) + { + return request.m_filterCallback(body, shape); + } + + // Overlap filter callbacks return true/false rather than Touch/Block/None + if constexpr (AZStd::is_same_v) + { + return true; + } + else + { + return AzPhysics::SceneQuery::QueryHitType::Touch; + } + } + + if constexpr (AZStd::is_same_v) + { + return false; + } + else + { + return AzPhysics::SceneQuery::QueryHitType::None; + } + }; + + // Execute the scene query modified for the time rewind. + AzPhysics::SceneQueryHits result = sceneInterface->QueryScene(sceneHandle, &netSceneQueryRequest); + return result; + } +} + +namespace Multiplayer +{ + namespace Physics + { + AzPhysics::SceneQueryHits RayCast(const AzPhysics::RayCastRequest& request) + { + return SceneQueryInternal(request); + } + + AzPhysics::SceneQueryHits ShapeCast(const AzPhysics::ShapeCastRequest& request) + { + return SceneQueryInternal(request); + } + + AzPhysics::SceneQueryHits Overlap(const AzPhysics::OverlapRequest& request) + { + return SceneQueryInternal(request); + } + } // namespace Physics +} // namespace Multiplayer diff --git a/Gems/Multiplayer/Code/multiplayer_files.cmake b/Gems/Multiplayer/Code/multiplayer_files.cmake index eb856a48db..28f32e02cc 100644 --- a/Gems/Multiplayer/Code/multiplayer_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_files.cmake @@ -35,6 +35,7 @@ set(FILES Include/Multiplayer/NetworkTime/INetworkTime.h Include/Multiplayer/NetworkTime/RewindableObject.h Include/Multiplayer/NetworkTime/RewindableObject.inl + Include/Multiplayer/Physics/PhysicsUtils.h Include/Multiplayer/ReplicationWindows/IReplicationWindow.h Source/Multiplayer_precompiled.cpp Source/Multiplayer_precompiled.h @@ -103,6 +104,7 @@ set(FILES Source/Pipeline/NetBindMarkerComponent.h Source/Pipeline/NetworkSpawnableHolderComponent.cpp Source/Pipeline/NetworkSpawnableHolderComponent.h + Source/Physics/PhysicsUtils.cpp Source/ReplicationWindows/NullReplicationWindow.cpp Source/ReplicationWindows/NullReplicationWindow.h Source/ReplicationWindows/ServerToClientReplicationWindow.cpp