Merge branch 'main' of https://github.com/aws-lumberyard/o3de into Spawnable/Instantiation/EntityIdReferenceFix
This commit is contained in:
@@ -20,10 +20,12 @@
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
//! Simple class for verifying that no concurrent access is occuring.
|
||||
//! Simple class for verifying that no concurrent access is occurring.
|
||||
//! This is *not* a synchronization primitive, and is intended simply for checking that no concurrency issues exist.
|
||||
//! It will be compiled out in release builds.
|
||||
//! Use concurrency_checker like a mutex (i.e. call soft_lock() and soft_unlock() around all instances of your data access).
|
||||
//! Use soft_lock_shared and soft_unlock_shared around places where multiple threads are allowed to have read access
|
||||
//! at the same time as long as nothing else already has a soft lock
|
||||
//! It will assert if there are multiple threads accessing the locked code/data at the same time.
|
||||
//! Expected use case is for defensive programming: when you do not expect any concurrent access within a system,
|
||||
//! but want to verify that it stays that way in the future, without incurring the overhead of a mutex.
|
||||
@@ -34,7 +36,7 @@ namespace AZStd
|
||||
{
|
||||
#ifdef AZ_CONCURRENCY_CHECKER_ENABLED
|
||||
uint32_t count = ++m_concurrencyCounter;
|
||||
AZ_Assert(count == 1, "Concurrency check failed. Multiple threads are trying to access data at the same time, or there is a lock/unlock mismatch.");
|
||||
AZ_Assert(count == 1 && m_sharedConcurrencyCounter == 0, "Concurrency check failed. Multiple threads are trying to access data at the same time, or there is a lock/unlock mismatch.");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -46,9 +48,27 @@ namespace AZStd
|
||||
#endif
|
||||
}
|
||||
|
||||
AZ_FORCE_INLINE void soft_lock_shared()
|
||||
{
|
||||
#ifdef AZ_CONCURRENCY_CHECKER_ENABLED
|
||||
AZ_Assert(m_concurrencyCounter == 0, "Concurrency check failed. A soft_lock_shared was attempted when there was already a soft_lock.");
|
||||
++m_sharedConcurrencyCounter;
|
||||
#endif
|
||||
}
|
||||
|
||||
AZ_FORCE_INLINE void soft_unlock_shared()
|
||||
{
|
||||
#ifdef AZ_CONCURRENCY_CHECKER_ENABLED
|
||||
AZ_Assert(m_sharedConcurrencyCounter != 0, "Concurrency check failed. There is a shared_lock/shared_unlock mismatch.");
|
||||
--m_sharedConcurrencyCounter;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
#ifdef AZ_CONCURRENCY_CHECKER_ENABLED
|
||||
AZStd::atomic_uint32_t m_concurrencyCounter = 0;
|
||||
AZStd::atomic_uint32_t m_sharedConcurrencyCounter = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -293,15 +293,12 @@ namespace UnitTest
|
||||
{
|
||||
array_view<int> view({ 1,2,3,4 });
|
||||
|
||||
UnitTest::TestRunner::Instance().StartAssertTests();
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
|
||||
EXPECT_EQ(0, UnitTest::TestRunner::Instance().m_numAssertsFailed);
|
||||
view[4];
|
||||
EXPECT_EQ(1, UnitTest::TestRunner::Instance().m_numAssertsFailed);
|
||||
view[5];
|
||||
EXPECT_EQ(2, UnitTest::TestRunner::Instance().m_numAssertsFailed);
|
||||
|
||||
UnitTest::TestRunner::Instance().StopAssertTests();
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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 <AtomCore/std/parallel/concurrency_checker.h>
|
||||
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
|
||||
using namespace AZStd;
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class ConcurrencyCheckerTestFixture
|
||||
: public AllocatorsTestFixture
|
||||
{
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
AllocatorsFixture::SetUp();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(AllocatorsTestFixture, SoftLock_NoContention_NoAsserts)
|
||||
{
|
||||
concurrency_checker concurrencyChecker;
|
||||
concurrencyChecker.soft_lock();
|
||||
concurrencyChecker.soft_unlock();
|
||||
concurrencyChecker.soft_lock();
|
||||
concurrencyChecker.soft_unlock();
|
||||
}
|
||||
|
||||
TEST_F(AllocatorsTestFixture, SoftLock_AlreadyLocked_Assert)
|
||||
{
|
||||
concurrency_checker concurrencyChecker;
|
||||
concurrencyChecker.soft_lock();
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
concurrencyChecker.soft_lock();
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
}
|
||||
|
||||
TEST_F(AllocatorsTestFixture, SoftUnlock_NotAlreadyLocked_Assert)
|
||||
{
|
||||
concurrency_checker concurrencyChecker;
|
||||
concurrencyChecker.soft_lock();
|
||||
concurrencyChecker.soft_unlock();
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
concurrencyChecker.soft_unlock();
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
}
|
||||
|
||||
TEST_F(AllocatorsTestFixture, SoftLockShared_NoContention_NoAsserts)
|
||||
{
|
||||
concurrency_checker concurrencyChecker;
|
||||
// Multiple shared locks can be made at once,
|
||||
// as long as they are all unlocked before the next soft_lock
|
||||
concurrencyChecker.soft_lock_shared();
|
||||
concurrencyChecker.soft_lock_shared();
|
||||
concurrencyChecker.soft_unlock_shared();
|
||||
concurrencyChecker.soft_unlock_shared();
|
||||
|
||||
concurrencyChecker.soft_lock();
|
||||
concurrencyChecker.soft_unlock();
|
||||
|
||||
concurrencyChecker.soft_lock_shared();
|
||||
concurrencyChecker.soft_lock_shared();
|
||||
concurrencyChecker.soft_unlock_shared();
|
||||
concurrencyChecker.soft_unlock_shared();
|
||||
|
||||
concurrencyChecker.soft_lock();
|
||||
concurrencyChecker.soft_unlock();
|
||||
}
|
||||
|
||||
TEST_F(AllocatorsTestFixture, SoftLockShared_SharedLockAfterSoftLock_Assert)
|
||||
{
|
||||
concurrency_checker concurrencyChecker;
|
||||
|
||||
concurrencyChecker.soft_lock();
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
concurrencyChecker.soft_lock_shared();
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
}
|
||||
|
||||
TEST_F(AllocatorsTestFixture, SoftUnlockShared_NotAlreadyLocked_Assert)
|
||||
{
|
||||
concurrency_checker concurrencyChecker;
|
||||
concurrencyChecker.soft_lock_shared();
|
||||
concurrencyChecker.soft_unlock_shared();
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
concurrencyChecker.soft_unlock_shared();
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
set(FILES
|
||||
ArrayView.cpp
|
||||
ConcurrencyCheckerTests.cpp
|
||||
InstanceDatabase.cpp
|
||||
JsonSerializationUtilsTests.cpp
|
||||
lru_cache.cpp
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a pointer to the beginning of master vector of SmallAllocationGroups.
|
||||
/// Returns a pointer to the beginning of vector of SmallAllocationGroups.
|
||||
SmallAllocationGroup* ArrayHead()
|
||||
{
|
||||
return this - m_index;
|
||||
@@ -169,7 +169,7 @@ namespace AZ
|
||||
return m_marker == MARKER;
|
||||
}
|
||||
|
||||
/// Returns the master index of the SmallAllocationGroup containing this allocation
|
||||
/// Returns the index of the SmallAllocationGroup containing this allocation
|
||||
uint32_t GetSmallAllocationIndex() const
|
||||
{
|
||||
return (uint32_t)(m_data & 0xFFFFFFFF);
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace AZ
|
||||
// Afterwards use the AZ::IO::Path Append function append the filename as a child
|
||||
// of the framework directory
|
||||
AZ::IO::FixedMaxPathString fileName{ fullPath.Filename().Native() };
|
||||
fullPath.ReplaceFilename(AZ::IO::PathView((fileName + ".framework").c_str()));
|
||||
fullPath.ReplaceFilename(AZ::IO::PathView(AZStd::string_view(fileName + ".framework")));
|
||||
fullPath /= fileName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace AZ::IO
|
||||
// If used, the source path will be treated as the destination path
|
||||
// and no transformations will be done. Pass this flag when the path is to be the actual
|
||||
// path on the disk/in the packs and doesn't need adjustment (or after it has come through adjustments already)
|
||||
// if this is set, AdjustFileName will not map the input path into the master folder (Ex: Shaders will not be converted to Game\Shaders)
|
||||
// if this is set, AdjustFileName will not map the input path into the folder (Ex: Shaders will not be converted to Game\Shaders)
|
||||
FLAGS_PATH_REAL = 1 << 16,
|
||||
|
||||
// AdjustFileName will always copy the file path to the destination path:
|
||||
@@ -318,7 +318,6 @@ namespace AZ::IO
|
||||
virtual ArchiveFileIterator FindFirst(AZStd::string_view pDir, uint32_t nFlags = 0, bool bAllowUseFileSystem = false) = 0;
|
||||
virtual ArchiveFileIterator FindNext(AZ::IO::ArchiveFileIterator handle) = 0;
|
||||
virtual bool FindClose(AZ::IO::ArchiveFileIterator handle) = 0;
|
||||
// virtual bool IsOutOfDate(const char * szCompiledName, const char * szMasterFile)=0;
|
||||
//returns file modification time
|
||||
virtual IArchive::FileTime GetModificationTime(AZ::IO::HandleType fileHandle) = 0;
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace AZ::IO
|
||||
enum EPakFlags
|
||||
{
|
||||
// support for absolute and other complex path specifications -
|
||||
// all paths will be treated relatively to the current directory (normally MasterCD)
|
||||
// all paths will be treated relatively to the current directory
|
||||
FLAGS_ABSOLUTE_PATHS = 1,
|
||||
|
||||
// if this is set, the object will only understand relative to the zip file paths,
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <AzFramework/Physics/Collision/CollisionGroups.h>
|
||||
#include <AzFramework/Physics/Collision/CollisionLayers.h>
|
||||
#include <AzFramework/Physics/Common/PhysicsTypes.h>
|
||||
#include <AzFramework/Physics/Common/PhysicsSimulatedBody.h>
|
||||
#include <AzFramework/Physics/Configuration/SimulatedBodyConfiguration.h>
|
||||
|
||||
@@ -36,7 +37,7 @@ namespace Physics
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
AZStd::string m_name;
|
||||
ShapeConfigurationList m_shapes;
|
||||
AzPhysics::ShapeColliderPairList m_shapes;
|
||||
};
|
||||
|
||||
class CharacterColliderConfiguration
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Physics
|
||||
classElement.RemoveElement(shapesIndex);
|
||||
|
||||
// add a new vector in the new format
|
||||
const int newShapesIndex = classElement.AddElement<ShapeConfigurationList>(context, "shapes");
|
||||
const int newShapesIndex = classElement.AddElement<AzPhysics::ShapeColliderPairList>(context, "shapes");
|
||||
if (newShapesIndex != -1)
|
||||
{
|
||||
AZ::SerializeContext::DataElementNode& newShapesElement = classElement.GetSubElement(newShapesIndex);
|
||||
@@ -65,7 +65,9 @@ namespace Physics
|
||||
// convert the old shapes into the new format and add to the vector
|
||||
for (AZ::SerializeContext::DataElementNode shape : shapesCopy)
|
||||
{
|
||||
const int pairIndex = newShapesElement.AddElementWithData<ShapeConfigurationPair>(context, "element", ShapeConfigurationPair());
|
||||
const int pairIndex = newShapesElement.AddElementWithData<AzPhysics::ShapeColliderPair>(
|
||||
context, "element", AzPhysics::ShapeColliderPair());
|
||||
|
||||
AZ::SerializeContext::DataElementNode& pairElement = newShapesElement.GetSubElement(pairIndex);
|
||||
|
||||
ColliderConfiguration colliderConfig;
|
||||
@@ -131,8 +133,8 @@ namespace Physics
|
||||
AZ::SerializeContext::DataElementNode* baseBaseClass1 = baseClass1->FindSubElement(AZ_CRC("BaseClass1", 0xd4925735));
|
||||
if (baseBaseClass1 && baseBaseClass1->FindSubElementAndGetData<AZStd::string>(AZ_CRC("name", 0x5e237e06), name))
|
||||
{
|
||||
ShapeConfigurationList shapes;
|
||||
if (nodeElement.FindSubElementAndGetData<ShapeConfigurationList>(AZ_CRC("shapes", 0x93dba512), shapes))
|
||||
AzPhysics::ShapeColliderPairList shapes;
|
||||
if (nodeElement.FindSubElementAndGetData<AzPhysics::ShapeColliderPairList>(AZ_CRC("shapes", 0x93dba512), shapes))
|
||||
{
|
||||
CharacterColliderNodeConfiguration newColliderNodeConfig;
|
||||
newColliderNodeConfig.m_name = name;
|
||||
|
||||
@@ -70,7 +70,10 @@ namespace AzPhysics
|
||||
using SimulatedBodyHandleList = AZStd::vector<SimulatedBodyHandle>;
|
||||
|
||||
//! Helper used for pairing the ShapeConfiguration and ColliderConfiguration together which is used when creating a Simulated Body.
|
||||
using ShapeColliderPair = AZStd::pair<Physics::ColliderConfiguration*, Physics::ShapeConfiguration*>;
|
||||
using ShapeColliderPair = AZStd::pair<
|
||||
AZStd::shared_ptr<Physics::ColliderConfiguration>,
|
||||
AZStd::shared_ptr<Physics::ShapeConfiguration>>;
|
||||
using ShapeColliderPairList = AZStd::vector<ShapeColliderPair>;
|
||||
|
||||
//! Flags used to specifying which properties of a body to compute.
|
||||
enum class MassComputeFlags : AZ::u8
|
||||
|
||||
@@ -80,9 +80,6 @@ namespace Physics
|
||||
void OnContactOffsetChanged();
|
||||
};
|
||||
|
||||
using ShapeConfigurationPair = AZStd::pair<AZStd::shared_ptr<ColliderConfiguration>, AZStd::shared_ptr<ShapeConfiguration>>;
|
||||
using ShapeConfigurationList = AZStd::vector<ShapeConfigurationPair>;
|
||||
|
||||
struct RayCastRequest;
|
||||
|
||||
class Shape
|
||||
|
||||
@@ -264,12 +264,12 @@ namespace AzFramework
|
||||
// SampleRPC =
|
||||
// {
|
||||
// // Two callbacks can be registered to the NetRPC
|
||||
// // A function to be invoked on the Master - OnMaster
|
||||
// // A function to be invoked on the main server - OnServer
|
||||
// // and a function to be invoked on the Proxy - OnProxy
|
||||
// //
|
||||
// // Every NetRPC needs to have a valid OnMaster function, while OnProxy is optional.
|
||||
// OnMaster = function()
|
||||
// Debug.Log("Function to be invoked on the Master.");
|
||||
// // Every NetRPC needs to have a valid OnServer function, while OnProxy is optional.
|
||||
// OnServer = function()
|
||||
// Debug.Log("Function to be invoked on the server.");
|
||||
// end
|
||||
//
|
||||
// OnProxy = function()
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Neighborhood {
|
||||
//---------------------------------------------------------------------
|
||||
void NeighborReplica::OnReplicaActivate(const GridMate::ReplicaContext& /*rc*/)
|
||||
{
|
||||
// TODO: Should we send the message to ourselves as well (master)?
|
||||
// TODO: Should we send the message to ourselves as well?
|
||||
if (IsProxy())
|
||||
{
|
||||
AZ_Assert(m_persistentName.Get().c_str(), "Received NeighborReplica with missing persistent name!");
|
||||
@@ -52,7 +52,7 @@ namespace Neighborhood {
|
||||
//---------------------------------------------------------------------
|
||||
void NeighborReplica::OnReplicaDeactivate(const GridMate::ReplicaContext& /*rc*/)
|
||||
{
|
||||
// TODO: Should we send the message to ourselves as well (master)?
|
||||
// TODO: Should we send the message to ourselves as well?
|
||||
if (IsProxy())
|
||||
{
|
||||
EBUS_EVENT(NeighborhoodBus, OnNodeLeft, *this);
|
||||
|
||||
@@ -30,7 +30,8 @@ namespace AzFramework
|
||||
AZ_CVAR(float, ed_cameraSystemOrbitDollyScrollSpeed, 0.02f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemOrbitDollyCursorSpeed, 0.01f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemScrollTranslateSpeed, 0.02f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemMaxOrbitDistance, 60.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemMinOrbitDistance, 6.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemMaxOrbitDistance, 50.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemLookSmoothness, 5.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemTranslateSmoothness, 5.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemRotateSpeed, 0.005f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
@@ -532,20 +533,39 @@ namespace AzFramework
|
||||
|
||||
if (Beginning())
|
||||
{
|
||||
float hit_distance = 0.0f;
|
||||
AZ::Plane::CreateFromNormalAndPoint(AZ::Vector3::CreateAxisZ(), AZ::Vector3::CreateAxisZ(ed_cameraSystemDefaultPlaneHeight))
|
||||
.CastRay(targetCamera.Translation(), targetCamera.Rotation().GetBasisY(), hit_distance);
|
||||
const auto hasLookAt = [&nextCamera, &targetCamera, lookAtFn = m_lookAtFn] {
|
||||
if (lookAtFn)
|
||||
{
|
||||
if (const auto lookAt = lookAtFn())
|
||||
{
|
||||
auto transform = AZ::Transform::CreateLookAt(targetCamera.m_lookAt, *lookAt);
|
||||
nextCamera.m_lookDist = -lookAt->GetDistance(targetCamera.m_lookAt);
|
||||
UpdateCameraFromTransform(nextCamera, transform);
|
||||
|
||||
if (hit_distance > 0.0f)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}();
|
||||
|
||||
if (!hasLookAt)
|
||||
{
|
||||
hit_distance = AZStd::min<float>(hit_distance, ed_cameraSystemMaxOrbitDistance);
|
||||
nextCamera.m_lookDist = -hit_distance;
|
||||
nextCamera.m_lookAt = targetCamera.Translation() + targetCamera.Rotation().GetBasisY() * hit_distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextCamera.m_lookDist = -ed_cameraSystemMaxOrbitDistance;
|
||||
nextCamera.m_lookAt = targetCamera.Translation() + targetCamera.Rotation().GetBasisY() * ed_cameraSystemMaxOrbitDistance;
|
||||
float hit_distance = 0.0f;
|
||||
AZ::Plane::CreateFromNormalAndPoint(AZ::Vector3::CreateAxisZ(), AZ::Vector3::CreateAxisZ(ed_cameraSystemDefaultPlaneHeight))
|
||||
.CastRay(targetCamera.Translation(), targetCamera.Rotation().GetBasisY(), hit_distance);
|
||||
|
||||
if (hit_distance > 0.0f)
|
||||
{
|
||||
hit_distance = AZStd::min<float>(hit_distance, ed_cameraSystemMaxOrbitDistance);
|
||||
nextCamera.m_lookDist = -hit_distance;
|
||||
nextCamera.m_lookAt = targetCamera.Translation() + targetCamera.Rotation().GetBasisY() * hit_distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextCamera.m_lookDist = -ed_cameraSystemMinOrbitDistance;
|
||||
nextCamera.m_lookAt =
|
||||
targetCamera.Translation() + targetCamera.Rotation().GetBasisY() * ed_cameraSystemMinOrbitDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -199,6 +199,7 @@ namespace AzFramework
|
||||
public:
|
||||
explicit RotateCameraInput(InputChannelId rotateChannelId);
|
||||
|
||||
// CameraInput overrides ...
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
@@ -239,6 +240,7 @@ namespace AzFramework
|
||||
public:
|
||||
PanCameraInput(InputChannelId panChannelId, PanAxesFn panAxesFn);
|
||||
|
||||
// CameraInput overrides ...
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
@@ -279,6 +281,7 @@ namespace AzFramework
|
||||
public:
|
||||
explicit TranslateCameraInput(TranslationAxesFn translationAxesFn);
|
||||
|
||||
// CameraInput overrides ...
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
void ResetImpl() override;
|
||||
@@ -348,6 +351,7 @@ namespace AzFramework
|
||||
class OrbitDollyScrollCameraInput : public CameraInput
|
||||
{
|
||||
public:
|
||||
// CameraInput overrides ...
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
};
|
||||
@@ -357,6 +361,7 @@ namespace AzFramework
|
||||
public:
|
||||
explicit OrbitDollyCursorMoveCameraInput(InputChannelId dollyChannelId);
|
||||
|
||||
// CameraInput overrides ...
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
@@ -367,6 +372,7 @@ namespace AzFramework
|
||||
class ScrollTranslationCameraInput : public CameraInput
|
||||
{
|
||||
public:
|
||||
// CameraInput overrides ...
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
};
|
||||
@@ -374,16 +380,32 @@ namespace AzFramework
|
||||
class OrbitCameraInput : public CameraInput
|
||||
{
|
||||
public:
|
||||
using LookAtFn = AZStd::function<AZStd::optional<AZ::Vector3>()>;
|
||||
|
||||
// CameraInput overrides ...
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
bool Exclusive() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool Exclusive() const override;
|
||||
|
||||
Cameras m_orbitCameras;
|
||||
|
||||
//! Override the default behavior for how a look-at point is calculated.
|
||||
void SetLookAtFn(const LookAtFn& lookAtFn);
|
||||
|
||||
private:
|
||||
LookAtFn m_lookAtFn;
|
||||
};
|
||||
|
||||
inline void OrbitCameraInput::SetLookAtFn(const LookAtFn& lookAtFn)
|
||||
{
|
||||
m_lookAtFn = lookAtFn;
|
||||
}
|
||||
|
||||
inline bool OrbitCameraInput::Exclusive() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
struct WindowSize;
|
||||
|
||||
//! Map from a generic InputChannel event to a camera specific InputEvent.
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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 <AzQtComponents/Utilities/SelectionProxyModel.h>
|
||||
#include <QAbstractProxyModel>
|
||||
|
||||
namespace AzQtComponents
|
||||
{
|
||||
SelectionProxyModel::SelectionProxyModel(QItemSelectionModel* sourceSelectionModel, QAbstractProxyModel* proxyModel, QObject* parent)
|
||||
: QItemSelectionModel(proxyModel, parent)
|
||||
, m_sourceSelectionModel(sourceSelectionModel)
|
||||
{
|
||||
connect(sourceSelectionModel, &QItemSelectionModel::selectionChanged, this, &SelectionProxyModel::OnSourceSelectionChanged);
|
||||
connect(sourceSelectionModel, &QItemSelectionModel::currentChanged, this, &SelectionProxyModel::OnSourceSelectionCurrentChanged);
|
||||
connect(proxyModel, &QAbstractItemModel::rowsInserted, this, &SelectionProxyModel::OnProxyModelRowsInserted);
|
||||
connect(this, &QItemSelectionModel::selectionChanged, this, &SelectionProxyModel::OnProxySelectionChanged);
|
||||
|
||||
// Find the chain of proxy models
|
||||
QAbstractProxyModel* sourceProxyModel = proxyModel;
|
||||
while (sourceProxyModel)
|
||||
{
|
||||
m_proxyModels.push_back(sourceProxyModel);
|
||||
sourceProxyModel = qobject_cast<QAbstractProxyModel*>(sourceProxyModel->sourceModel());
|
||||
}
|
||||
|
||||
const QItemSelection currentSelection = mapFromSource(m_sourceSelectionModel->selection());
|
||||
QItemSelectionModel::select(currentSelection, QItemSelectionModel::ClearAndSelect);
|
||||
|
||||
const QModelIndex currentModelIndex = mapFromSource(m_sourceSelectionModel->currentIndex());
|
||||
QItemSelectionModel::setCurrentIndex(currentModelIndex, QItemSelectionModel::ClearAndSelect);
|
||||
}
|
||||
|
||||
void SelectionProxyModel::setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
|
||||
{
|
||||
const QModelIndex sourcetIndex = mapToSource(index);
|
||||
m_sourceSelectionModel->setCurrentIndex(sourcetIndex, command);
|
||||
}
|
||||
|
||||
void SelectionProxyModel::select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
|
||||
{
|
||||
const QModelIndex sourceIndex = mapToSource(index);
|
||||
m_sourceSelectionModel->select(sourceIndex, command);
|
||||
}
|
||||
|
||||
void SelectionProxyModel::select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command)
|
||||
{
|
||||
const QItemSelection sourceSelection = mapToSource(selection);
|
||||
m_sourceSelectionModel->select(sourceSelection, command);
|
||||
}
|
||||
|
||||
void SelectionProxyModel::clear()
|
||||
{
|
||||
m_sourceSelectionModel->clear();
|
||||
}
|
||||
|
||||
void SelectionProxyModel::reset()
|
||||
{
|
||||
m_sourceSelectionModel->reset();
|
||||
}
|
||||
|
||||
void SelectionProxyModel::clearCurrentIndex()
|
||||
{
|
||||
m_sourceSelectionModel->clearCurrentIndex();
|
||||
}
|
||||
|
||||
void SelectionProxyModel::OnSourceSelectionCurrentChanged(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous)
|
||||
{
|
||||
QModelIndex targetCurrent = mapFromSource(current);
|
||||
QItemSelectionModel::setCurrentIndex(targetCurrent, QItemSelectionModel::NoUpdate);
|
||||
}
|
||||
|
||||
void SelectionProxyModel::OnSourceSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
|
||||
{
|
||||
QItemSelection targetSelected = mapFromSource(selected);
|
||||
QItemSelection targetDeselected = mapFromSource(deselected);
|
||||
|
||||
QItemSelectionModel::select(targetSelected, QItemSelectionModel::Select);
|
||||
QItemSelectionModel::select(targetDeselected, QItemSelectionModel::Deselect);
|
||||
}
|
||||
|
||||
void SelectionProxyModel::OnProxySelectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
|
||||
{
|
||||
const QItemSelection sourceSelected = mapToSource(selected);
|
||||
const QItemSelection sourceDeselected = mapToSource(deselected);
|
||||
|
||||
// Disconnect from the selectionChanged signal in the source model to prevent recursion. We could also block the signals
|
||||
// of the source selection model, but someone else may be connected to its signals and expect to get an update.
|
||||
disconnect(m_sourceSelectionModel, &QItemSelectionModel::selectionChanged, this, &SelectionProxyModel::OnSourceSelectionChanged);
|
||||
if (selected.empty() && deselected.empty())
|
||||
{
|
||||
// Force the signal to fire
|
||||
emit m_sourceSelectionModel->selectionChanged({}, {});
|
||||
}
|
||||
else
|
||||
{
|
||||
m_sourceSelectionModel->select(sourceSelected, QItemSelectionModel::Select);
|
||||
m_sourceSelectionModel->select(sourceDeselected, QItemSelectionModel::Deselect);
|
||||
}
|
||||
connect(m_sourceSelectionModel, &QItemSelectionModel::selectionChanged, this, &SelectionProxyModel::OnSourceSelectionChanged);
|
||||
}
|
||||
|
||||
void SelectionProxyModel::OnProxyModelRowsInserted([[maybe_unused]] const QModelIndex& parent, [[maybe_unused]] int first, [[maybe_unused]] int last)
|
||||
{
|
||||
QModelIndex sourceIndex = m_sourceSelectionModel->currentIndex();
|
||||
QModelIndex targetIndex = mapFromSource(sourceIndex);
|
||||
if (targetIndex != currentIndex())
|
||||
{
|
||||
QItemSelectionModel::setCurrentIndex(targetIndex, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
|
||||
}
|
||||
|
||||
QItemSelection sourceSelection = m_sourceSelectionModel->selection();
|
||||
QItemSelection targetSelection = mapFromSource(sourceSelection);
|
||||
if (targetSelection != selection())
|
||||
{
|
||||
QItemSelectionModel::select(targetSelection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex SelectionProxyModel::mapFromSource(const QModelIndex& sourceIndex)
|
||||
{
|
||||
QModelIndex mappedIndex = sourceIndex;
|
||||
for (QVector<QAbstractProxyModel*>::const_reverse_iterator itProxy = m_proxyModels.rbegin(); itProxy != m_proxyModels.rend(); ++itProxy)
|
||||
{
|
||||
mappedIndex = (*itProxy)->mapFromSource(mappedIndex);
|
||||
}
|
||||
return mappedIndex;
|
||||
}
|
||||
|
||||
QItemSelection SelectionProxyModel::mapFromSource(const QItemSelection& sourceSelection)
|
||||
{
|
||||
QItemSelection mappedSelection = sourceSelection;
|
||||
for (QVector<QAbstractProxyModel*>::const_reverse_iterator itProxy = m_proxyModels.rbegin(); itProxy != m_proxyModels.rend(); ++itProxy)
|
||||
{
|
||||
mappedSelection = (*itProxy)->mapSelectionFromSource(mappedSelection);
|
||||
}
|
||||
return mappedSelection;
|
||||
}
|
||||
|
||||
QModelIndex SelectionProxyModel::mapToSource(const QModelIndex& targetIndex)
|
||||
{
|
||||
QModelIndex mappedIndex = targetIndex;
|
||||
for (QVector<QAbstractProxyModel*>::const_iterator itProxy = m_proxyModels.begin(); itProxy != m_proxyModels.end(); ++itProxy)
|
||||
{
|
||||
mappedIndex = (*itProxy)->mapToSource(mappedIndex);
|
||||
}
|
||||
return mappedIndex;
|
||||
}
|
||||
|
||||
QItemSelection SelectionProxyModel::mapToSource(const QItemSelection& targetSelection)
|
||||
{
|
||||
QItemSelection mappedSelection = targetSelection;
|
||||
for (QVector<QAbstractProxyModel*>::const_iterator itProxy = m_proxyModels.begin(); itProxy != m_proxyModels.end(); ++itProxy)
|
||||
{
|
||||
mappedSelection = (*itProxy)->mapSelectionToSource(mappedSelection);
|
||||
}
|
||||
return mappedSelection;
|
||||
}
|
||||
} // namespace AzQtComponents
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzQtComponents/AzQtComponentsAPI.h>
|
||||
#include <QtCore/QItemSelectionModel>
|
||||
#include <QVector>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QAbstractProxyModel)
|
||||
|
||||
namespace AzQtComponents
|
||||
{
|
||||
//! This class is a QItemSelectionModel that syncs through proxy models and maintains
|
||||
//! selection. In Qt we can have a model being filtered/sorted by proxy models. If the
|
||||
//! selection model is connected to the original model, the view needs a new selection
|
||||
//! model that understands the filtering. This class does that conversion.
|
||||
//! @Note: this class does not support changing proxy models (anywhere in the chain).
|
||||
//! The class will have to be recreated with the new proxy model.
|
||||
class AZ_QT_COMPONENTS_API SelectionProxyModel
|
||||
: public QItemSelectionModel
|
||||
{
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
SelectionProxyModel(QItemSelectionModel* sourceSelectionModel, QAbstractProxyModel* proxyModel, QObject* parent = nullptr);
|
||||
|
||||
void setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command) override;
|
||||
void select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command) override;
|
||||
void select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) override;
|
||||
void clear() override;
|
||||
void reset() override;
|
||||
void clearCurrentIndex() override;
|
||||
|
||||
private slots:
|
||||
void OnSourceSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
|
||||
void OnSourceSelectionCurrentChanged(const QModelIndex& current, const QModelIndex& previous);
|
||||
void OnProxySelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
|
||||
void OnProxyModelRowsInserted(const QModelIndex& parent, int first, int last);
|
||||
|
||||
private:
|
||||
QModelIndex mapFromSource(const QModelIndex& sourceIndex);
|
||||
QItemSelection mapFromSource(const QItemSelection& sourceSelection);
|
||||
|
||||
QModelIndex mapToSource(const QModelIndex& targetIndex);
|
||||
QItemSelection mapToSource(const QItemSelection& targetSelection);
|
||||
|
||||
// Contains the chain of proxy models that leads us to the real model. The outer-most proxy model
|
||||
// comes first and is followed by inner proxy models.
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
QVector<QAbstractProxyModel*> m_proxyModels;
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
QItemSelectionModel* m_sourceSelectionModel;
|
||||
};
|
||||
} // namespace AzQtComponents
|
||||
@@ -287,6 +287,8 @@ set(FILES
|
||||
Utilities/ScreenUtilities.cpp
|
||||
Utilities/ScreenGrabber.h
|
||||
Utilities/ScopedCleanup.h
|
||||
Utilities/SelectionProxyModel.cpp
|
||||
Utilities/SelectionProxyModel.h
|
||||
Utilities/TextUtilities.cpp
|
||||
Utilities/TextUtilities.h
|
||||
)
|
||||
|
||||
@@ -296,7 +296,7 @@ DefaultTrafficControl::OnReceived(TrafficControlConnectionId id, DataGramControl
|
||||
if (m_maxRecvPackets != 0)
|
||||
{
|
||||
--cd->m_recvPacketAllowance;
|
||||
if (cd->m_recvPacketAllowance == 0) // hit the limit -> let's blacklist connection
|
||||
if (cd->m_recvPacketAllowance == 0) // hit the limit
|
||||
{
|
||||
cd->m_canReceiveData = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user