Merge branch 'main' into ly-as-sdk/LYN-2948

# Conflicts:
#	CMakeLists.txt
This commit is contained in:
pappeste
2021-05-10 14:36:20 -07:00
421 changed files with 13429 additions and 27863 deletions
@@ -14,6 +14,7 @@
#include <AzCore/Component/Entity.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Math/Sfmt.h>
#include <AzCore/Math/Crc.h>
@@ -173,7 +174,11 @@ namespace AZ
//=========================================================================
void ComponentDescriptor::ReleaseDescriptor()
{
EBUS_EVENT(ComponentApplicationBus, UnregisterComponentDescriptor, this);
AZ::ComponentApplicationRequests* componentApplication = AZ::Interface<AZ::ComponentApplicationRequests>::Get();
if (componentApplication != nullptr)
{
componentApplication->UnregisterComponentDescriptor(this);
}
delete this;
}
} // namespace AZ
@@ -526,6 +526,11 @@ namespace AZ
// are destroyed
m_commandLine = {};
m_entityAddedEvent.DisconnectAllHandlers();
m_entityRemovedEvent.DisconnectAllHandlers();
m_entityActivatedEvent.DisconnectAllHandlers();
m_entityDeactivatedEvent.DisconnectAllHandlers();
DestroyAllocator();
}
@@ -980,6 +985,26 @@ namespace AZ
handler.Connect(m_entityRemovedEvent);
}
void ComponentApplication::RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler& handler)
{
handler.Connect(m_entityActivatedEvent);
}
void ComponentApplication::RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler& handler)
{
handler.Connect(m_entityDeactivatedEvent);
}
void ComponentApplication::SignalEntityActivated(AZ::Entity* entity)
{
m_entityActivatedEvent.Signal(entity);
}
void ComponentApplication::SignalEntityDeactivated(AZ::Entity* entity)
{
m_entityDeactivatedEvent.Signal(entity);
}
//=========================================================================
// AddEntity
// [5/30/2012]
@@ -204,6 +204,10 @@ namespace AZ
void UnregisterComponentDescriptor(const ComponentDescriptor* descriptor) override final;
void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler& handler) override final;
void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler& handler) override final;
void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler& handler) override final;
void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler& handler) override final;
void SignalEntityActivated(Entity* entity) override final;
void SignalEntityDeactivated(Entity* entity) override final;
bool AddEntity(Entity* entity) override;
bool RemoveEntity(Entity* entity) override;
bool DeleteEntity(const EntityId& id) override;
@@ -382,6 +386,8 @@ namespace AZ
AZStd::unique_ptr<SettingsRegistryInterface> m_settingsRegistry;
EntityAddedEvent m_entityAddedEvent;
EntityRemovedEvent m_entityRemovedEvent;
EntityAddedEvent m_entityActivatedEvent;
EntityRemovedEvent m_entityDeactivatedEvent;
AZ::IConsole* m_console{};
Descriptor m_descriptor;
bool m_isStarted{ false };
@@ -72,6 +72,8 @@ namespace AZ
using EntityAddedEvent = AZ::Event<AZ::Entity*>;
using EntityRemovedEvent = AZ::Event<AZ::Entity*>;
using EntityActivatedEvent = AZ::Event<AZ::Entity*>;
using EntityDeactivatedEvent = AZ::Event<AZ::Entity*>;
//! Interface that components can use to make requests of the main application.
class ComponentApplicationRequests
@@ -102,6 +104,22 @@ namespace AZ
//! @param handler the event handler to signal.
virtual void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler& handler) = 0;
//! Registers an event handler that will be signalled whenever an entity is added.
//! @param handler the event handler to signal.
virtual void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler& handler) = 0;
//! Registers an event handler that will be signalled whenever an entity is removed.
//! @param handler the event handler to signal.
virtual void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler& handler) = 0;
//! Signals that the provided entity has been activated.
//! @param entity the entity being activated.
virtual void SignalEntityActivated(AZ::Entity* entity) = 0;
//! Signals that the provided entity has been deactivated.
//! @param entity the entity being deactivated.
virtual void SignalEntityDeactivated(AZ::Entity* entity) = 0;
//! Adds an entity to the application's registry.
//! Calling Init() on an entity automatically performs this operation.
//! @param entity A pointer to the entity to add to the application's registry.
@@ -112,7 +112,11 @@ namespace AZ
{
EBUS_EVENT(EntitySystemBus, OnEntityDestruction, m_id);
EBUS_EVENT_ID(m_id, EntityBus, OnEntityDestruction, m_id);
EBUS_EVENT(ComponentApplicationBus, RemoveEntity, this);
AZ::ComponentApplicationRequests* componentApplication = AZ::Interface<AZ::ComponentApplicationRequests>::Get();
if (componentApplication != nullptr)
{
componentApplication->RemoveEntity(this);
}
m_stateEvent.Signal(State::Init, State::Destroying);
}
@@ -216,12 +220,22 @@ namespace AZ
EBUS_EVENT_ID(m_id, EntityBus, OnEntityActivated, m_id);
EBUS_EVENT(EntitySystemBus, OnEntityActivated, m_id);
AZ::ComponentApplicationRequests* componentApplication = AZ::Interface<AZ::ComponentApplicationRequests>::Get();
if (componentApplication != nullptr)
{
componentApplication->SignalEntityActivated(this);
}
}
void Entity::Deactivate()
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzCore);
AZ::ComponentApplicationRequests* componentApplication = AZ::Interface<AZ::ComponentApplicationRequests>::Get();
if (componentApplication != nullptr)
{
componentApplication->SignalEntityDeactivated(this);
}
EBUS_EVENT_ID(m_id, EntityBus, OnEntityDeactivated, m_id);
EBUS_EVENT(EntitySystemBus, OnEntityDeactivated, m_id);
@@ -126,9 +126,11 @@ namespace AZ
char buffer[MaxLogBufferSize];
const AZStd::size_t length = azvsnprintf(buffer, MaxLogBufferSize, format, args);
buffer[AZStd::min<AZStd::size_t>(length, MaxLogBufferSize - 2)] = '\n';
buffer[AZStd::min<AZStd::size_t>(length + 1, MaxLogBufferSize - 1)] = '\0';
m_logEvent.Signal(level, buffer, file, function, line);
// Force a new-line before calling the AZ::Debug::Trace functions, as they assume a newline is present
buffer[AZStd::min<AZStd::size_t>(length + 1, MaxLogBufferSize - 2)] = '\n';
switch (level)
{
case LogLevel::Warn:
@@ -142,8 +144,6 @@ namespace AZ
AZ::Debug::Trace::Output("Logger", buffer);
break;
}
m_logEvent.Signal(level, buffer, file, function, line);
}
void LoggerSystemComponent::SetLevel(const AZ::ConsoleCommandContainer& arguments)
@@ -233,6 +233,14 @@ namespace AZ
AZ_Assert(handler->m_event == this, "Entry event does not match");
handler->Disconnect();
}
// Free up any owned memory
AZStd::vector<Handler*> freeHandlers;
m_handlers.swap(freeHandlers);
AZStd::vector<Handler*> freeAdds;
m_addList.swap(freeAdds);
AZStd::stack<size_t> freeFree;
m_freeList.swap(freeFree);
}
+10 -9
View File
@@ -13,16 +13,17 @@
#pragma once
#include <AzCore/base.h>
#include <AzCore/std/math.h>
#include <AzCore/std/typetraits/conditional.h>
#include <AzCore/std/typetraits/is_integral.h>
#include <AzCore/std/typetraits/is_signed.h>
#include <AzCore/std/typetraits/is_unsigned.h>
#include <AzCore/std/utils.h>
#include <math.h>
#include <float.h>
#include <limits>
#include <cmath>
#include <math.h>
#include <utility>
#include <AzCore/std/typetraits/conditional.h>
#include <AzCore/std/typetraits/is_integral.h>
// We have a separate inline define for math functions.
// The performance of these functions is very sensitive to inlining, and some compilers don't deal well with this.
@@ -308,12 +309,12 @@ namespace AZ
AZ_MATH_INLINE bool IsClose(float a, float b, float tolerance = Constants::Tolerance)
{
return (fabsf(a - b) <= tolerance);
return (AZStd::abs(a - b) <= tolerance);
}
AZ_MATH_INLINE bool IsClose(double a, double b, double tolerance = Constants::Tolerance)
{
return (fabs(a - b) <= tolerance);
return (AZStd::abs(a - b) <= tolerance);
}
//! Returns x >= 0.0f ? 1.0f : -1.0f.
@@ -402,12 +403,12 @@ namespace AZ
AZ_MATH_INLINE float GetAbs(float a)
{
return fabsf(a);
return AZStd::abs(a);
}
AZ_MATH_INLINE double GetAbs(double a)
{
return std::abs(a);
return AZStd::abs(a);
}
AZ_MATH_INLINE float GetMod(float a, float b)
@@ -441,7 +442,7 @@ namespace AZ
template<typename T>
AZ_MATH_INLINE bool IsCloseMag(T x, T y, T epsilonValue = std::numeric_limits<T>::epsilon())
{
return (std::fabs(x - y) <= epsilonValue * GetMax<T>(GetMax<T>(T(1.0), std::fabs(x)), std::fabs(y)));
return (AZStd::abs(x - y) <= epsilonValue * GetMax<T>(GetMax<T>(T(1.0), AZStd::abs(x)), AZStd::abs(y)));
}
//! ClampIfCloseMag(x, y, epsilon) returns y when x and y are within epsilon of each other (taking magnitude into account). Otherwise returns x.
@@ -53,6 +53,10 @@ namespace AZ
//! RemoveableByUser : A bool which determines if the component can be removed by the user.
//! Setting this to false prevents the user from removing this component. Default behavior is removeable by user.
const static AZ::Crc32 RemoveableByUser = AZ_CRC("RemoveableByUser", 0x32c7fd50);
//! An int which, if specified, causes a component to be forced to a particular position in the sorted list of
//! components on an entity, and prevents dragging or moving operations which would affect that position.
const static AZ::Crc32 FixedComponentListIndex = AZ_CRC_CE("FixedComponentListIndex");
const static AZ::Crc32 AppearsInAddComponentMenu = AZ_CRC("AppearsInAddComponentMenu", 0x53790e31);
const static AZ::Crc32 ForceAutoExpand = AZ_CRC("ForceAutoExpand", 0x1a5c79d2); // Ignores expansion state set by user, enforces expansion.
const static AZ::Crc32 AutoExpand = AZ_CRC("AutoExpand", 0x306ff5c0); // Expands automatically unless user changes expansion state.
@@ -33,6 +33,10 @@ namespace UnitTest
MOCK_METHOD1(UnregisterComponentDescriptor, void (const AZ::ComponentDescriptor*));
MOCK_METHOD1(RegisterEntityAddedEventHandler, void(AZ::EntityAddedEvent::Handler&));
MOCK_METHOD1(RegisterEntityRemovedEventHandler, void(AZ::EntityRemovedEvent::Handler&));
MOCK_METHOD1(RegisterEntityActivatedEventHandler, void(AZ::EntityActivatedEvent::Handler&));
MOCK_METHOD1(RegisterEntityDeactivatedEventHandler, void(AZ::EntityDeactivatedEvent::Handler&));
MOCK_METHOD1(SignalEntityActivated, void(AZ::Entity*));
MOCK_METHOD1(SignalEntityDeactivated, void(AZ::Entity*));
MOCK_METHOD1(RemoveEntity, bool (AZ::Entity*));
MOCK_METHOD1(DeleteEntity, bool (const AZ::EntityId&));
MOCK_METHOD1(GetEntityName, AZStd::string (const AZ::EntityId&));
+6 -1
View File
@@ -169,5 +169,10 @@ namespace AZ::Utils
template AZ::Outcome<AZStd::vector<int8_t>, AZStd::string> ReadFile(AZStd::string_view filePath, size_t maxFileSize);
template AZ::Outcome<AZStd::vector<uint8_t>, AZStd::string> ReadFile(AZStd::string_view filePath, size_t maxFileSize);
AZ::IO::FixedMaxPathString GetO3deManifestDirectory()
{
AZ::IO::FixedMaxPath path = GetHomeDirectory();
path /= ".o3de";
return path.Native();
}
}
@@ -88,6 +88,9 @@ namespace AZ
//! Retrieves the project name from the settings registry
AZ::SettingsRegistryInterface::FixedValueString GetProjectName();
//! Retrieves the full directory to the Home directory, i.e. "<userhome> or overrideHomeDirectory"
AZ::IO::FixedMaxPathString GetHomeDirectory();
//! Retrieves the full directory to the O3DE manifest directory, i.e. "<userhome>/.o3de"
AZ::IO::FixedMaxPathString GetO3deManifestDirectory();
@@ -31,6 +31,7 @@ set(FILES
iterator.h
limits.h
numeric.h
math.h
optional.h
ratio.h
reference_wrapper.h
+20
View File
@@ -0,0 +1,20 @@
/*
* 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 <cmath>
namespace AZStd
{
using std::abs;
}
@@ -14,7 +14,7 @@
namespace AZ::Utils
{
AZ::IO::FixedMaxPathString GetO3deManifestDirectory()
AZ::IO::FixedMaxPathString GetHomeDirectory()
{
return {};
}
@@ -25,8 +25,19 @@ namespace AZ
void NativeErrorMessageBox(const char*, const char*) {}
AZ::IO::FixedMaxPathString GetO3deManifestDirectory()
AZ::IO::FixedMaxPathString GetHomeDirectory()
{
constexpr AZStd::string_view overrideHomeDirKey = "/Amazon/Settings/override_home_dir";
AZ::IO::FixedMaxPathString overrideHomeDir;
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
{
if (settingsRegistry->Get(overrideHomeDir, overrideHomeDirKey))
{
AZ::IO::FixedMaxPath path{overrideHomeDir};
return path.Native();
}
}
if (const char* homePath = std::getenv("HOME"); homePath != nullptr)
{
AZ::IO::FixedMaxPath path{homePath};
@@ -22,15 +22,25 @@ namespace AZ::Utils
::MessageBox(0, message, title, MB_OK | MB_ICONERROR);
}
AZ::IO::FixedMaxPathString GetO3deManifestDirectory()
AZ::IO::FixedMaxPathString GetHomeDirectory()
{
constexpr AZStd::string_view overrideHomeDirKey = "/Amazon/Settings/override_home_dir";
AZ::IO::FixedMaxPathString overrideHomeDir;
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
{
if (settingsRegistry->Get(overrideHomeDir, overrideHomeDirKey))
{
AZ::IO::FixedMaxPath path{overrideHomeDir};
return path.Native();
}
}
char userProfileBuffer[AZ::IO::MaxPathLength]{};
size_t variableSize = 0;
auto err = getenv_s(&variableSize, userProfileBuffer, AZ::IO::MaxPathLength, "USERPROFILE");
if (!err)
{
AZ::IO::FixedMaxPath path{ userProfileBuffer };
path /= ".o3de";
return path.Native();
}
@@ -49,9 +49,13 @@ namespace UnitTest
// ComponentApplicationBus
AZ::ComponentApplication* GetApplication() override { return nullptr; }
void RegisterComponentDescriptor(const AZ::ComponentDescriptor*) override {}
void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override {}
void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override {}
void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override {}
void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override {}
void RegisterEntityActivatedEventHandler(AZ::EntityActivatedEvent::Handler&) override {}
void RegisterEntityDeactivatedEventHandler(AZ::EntityDeactivatedEvent::Handler&) override {}
void SignalEntityActivated(AZ::Entity*) override {}
void SignalEntityDeactivated(AZ::Entity*) override {}
bool AddEntity(AZ::Entity*) override { return true; }
bool RemoveEntity(AZ::Entity*) override { return true; }
bool DeleteEntity(const AZ::EntityId&) override { return true; }
@@ -1232,6 +1232,10 @@ namespace UnitTest
void UnregisterComponentDescriptor(const ComponentDescriptor*) override { }
void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler&) override { }
void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler&) override { }
void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { }
void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { }
void SignalEntityActivated(Entity*) override { }
void SignalEntityDeactivated(Entity*) override { }
bool AddEntity(Entity*) override { return false; }
bool RemoveEntity(Entity*) override { return false; }
bool DeleteEntity(const EntityId&) override { return false; }
@@ -1252,6 +1256,7 @@ namespace UnitTest
m_serializeContext.reset(aznew AZ::SerializeContext());
ComponentApplicationBus::Handler::BusConnect();
AZ::Interface<AZ::ComponentApplicationRequests>::Register(this);
AZ::AllocatorInstance<AZ::PoolAllocator>::Create();
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Create();
@@ -1270,6 +1275,7 @@ namespace UnitTest
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Destroy();
AZ::AllocatorInstance<AZ::PoolAllocator>::Destroy();
AZ::Interface<AZ::ComponentApplicationRequests>::Unregister(this);
ComponentApplicationBus::Handler::BusDisconnect();
}
@@ -51,7 +51,6 @@ namespace AZ::IO
: ArchiveLocationPriority::ePakPriorityFileFirst }; // Which file location to favor (loose vs. pak files)
int nMessageInvalidFileAccess{};
int nLogInvalidFileAccess{ IsReleaseConfig ? 0 : 1 };
int nLoadFrontendShaderCache{ FRONTEND_SHADER_CACHE_DEFAULT };
int nDisableNonLevelRelatedPaks{ 1 };
int nWarnOnPakAccessFails{ 1 }; // Whether to treat failed pak access as a warning or log message
int nSetLogLevel{ 3 };
@@ -36,6 +36,8 @@ namespace AzFramework
void NonUniformScaleComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC_CE("NonUniformScaleService"));
incompatible.push_back(AZ_CRC_CE("DebugDrawObbService"));
incompatible.push_back(AZ_CRC_CE("DebugDrawService"));
incompatible.push_back(AZ_CRC_CE("EMotionFXActorService"));
@@ -11,10 +11,12 @@
*/
#include <AzFramework/Components/TransformComponent.h>
#include <AzFramework/Visibility/EntityBoundsUnionBus.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/Math/Quaternion.h>
@@ -693,9 +695,8 @@ namespace AzFramework
parentId = handler->GetParentId();
}
#endif
AZ::Entity* parentEntity = nullptr;
EBUS_EVENT_RESULT(parentEntity, AZ::ComponentApplicationBus, FindEntity, parentEntityId);
AZ::ComponentApplicationRequests* componentApplication = AZ::Interface<AZ::ComponentApplicationRequests>::Get();
AZ::Entity* parentEntity = (componentApplication != nullptr) ? componentApplication->FindEntity(parentEntityId) : nullptr;
AZ_Assert(parentEntity, "We expect to have a parent entity associated with the provided parent's entity Id.");
if (parentEntity)
{
@@ -744,8 +745,8 @@ namespace AzFramework
m_parentId = parentId;
if (m_parentId.IsValid())
{
AZ::Entity* parentEntity = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(parentEntity, &AZ::ComponentApplicationBus::Events::FindEntity, m_parentId);
AZ::ComponentApplicationRequests* componentApplication = AZ::Interface<AZ::ComponentApplicationRequests>::Get();
AZ::Entity* parentEntity = (componentApplication != nullptr) ? componentApplication->FindEntity(m_parentId) : nullptr;
m_parentActive = parentEntity && (parentEntity->GetState() == AZ::Entity::State::Active);
m_onNewParentKeepWorldTM = isKeepWorldTM;
@@ -832,6 +833,12 @@ namespace AzFramework
EBUS_EVENT_PTR(m_notificationBus, AZ::TransformNotificationBus, OnTransformChanged, m_localTM, m_worldTM);
m_transformChangedEvent.Signal(m_localTM, m_worldTM);
AzFramework::IEntityBoundsUnion* boundsUnion = AZ::Interface<AzFramework::IEntityBoundsUnion>::Get();
if (boundsUnion != nullptr)
{
boundsUnion->OnTransformUpdated(GetEntity());
}
}
void TransformComponent::ComputeWorldTM()
@@ -93,6 +93,8 @@ namespace AzFramework
InitContext();
GameEntityContextRequestBus::Handler::BusConnect();
m_entityVisibilityBoundsUnionSystem.Connect();
}
//=========================================================================
@@ -100,6 +102,8 @@ namespace AzFramework
//=========================================================================
void GameEntityContextComponent::Deactivate()
{
m_entityVisibilityBoundsUnionSystem.Disconnect();
GameEntityContextRequestBus::Handler::BusDisconnect();
DestroyContext();
@@ -18,6 +18,7 @@
#include <AzCore/Component/Component.h>
#include <AzFramework/Entity/GameEntityContextBus.h>
#include <AzFramework/Entity/SliceGameEntityOwnershipService.h>
#include <AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.h>
#include "EntityContext.h"
@@ -91,6 +92,9 @@ namespace AzFramework
{
required.push_back(AZ_CRC("SliceSystemService", 0x1a5b7aad));
}
private:
AzFramework::EntityVisibilityBoundsUnionSystem m_entityVisibilityBoundsUnionSystem;
};
} // namespace AzFramework
@@ -139,7 +139,8 @@ namespace AzFramework
"Implementers of IntersectionRequestBus must also implement BoundsRequestBus to ensure valid "
"bounds are returned");
m_registeredEntities.Update({ entityId, CalculateEntityWorldBoundsUnion(entityId) });
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(entityId);
m_registeredEntities.Update({ entityId, CalculateEntityWorldBoundsUnion(entity) });
}
m_dirtyEntities.clear();
@@ -48,15 +48,21 @@ namespace AzFramework
};
//! The interface used by MultiViewportController to manage individual instances.
template <class TController>
class MultiViewportControllerInstanceInterface
{
public:
explicit MultiViewportControllerInstanceInterface(ViewportId viewport)
using ControllerType = TController;
MultiViewportControllerInstanceInterface(ViewportId viewport, ControllerType* controller)
: m_viewportId(viewport)
, m_controller(controller)
{
}
ViewportId GetViewportId() const { return m_viewportId; }
ControllerType* GetController() { return m_controller; }
const ControllerType* GetController() const { return m_controller; }
virtual bool HandleInputChannelEvent([[maybe_unused]]const ViewportControllerInputEvent& event) { return false; }
virtual void ResetInputChannels() {}
@@ -64,6 +70,7 @@ namespace AzFramework
private:
ViewportId m_viewportId;
ControllerType* m_controller;
};
} //namespace AzFramework
@@ -17,8 +17,8 @@ namespace AzFramework
MultiViewportController<TViewportControllerInstance, Priority>::~MultiViewportController()
{
static_assert(
AZStd::is_constructible<TViewportControllerInstance, ViewportId>::value,
"TViewportControllerInstance must implement a TViewportControllerInstance(ViewportId) constructor"
AZStd::is_same<TViewportControllerInstance, decltype(TViewportControllerInstance(0, nullptr))>::value,
"TViewportControllerInstance must implement a TViewportControllerInstance(ViewportId, ViewportController) constructor"
);
}
@@ -50,7 +50,7 @@ namespace AzFramework
template <class TViewportControllerInstance, ViewportControllerPriority Priority>
void MultiViewportController<TViewportControllerInstance, Priority>::RegisterViewportContext(ViewportId viewport)
{
m_instances[viewport] = AZStd::make_unique<TViewportControllerInstance>(viewport);
m_instances[viewport] = AZStd::make_unique<TViewportControllerInstance>(viewport, static_cast<typename TViewportControllerInstance::ControllerType*>(this));
}
template <class TViewportControllerInstance, ViewportControllerPriority Priority>
@@ -12,6 +12,7 @@
#pragma once
#include <AzCore/Component/Entity.h>
#include <AzCore/Component/ComponentBus.h>
#include <AzCore/Component/TransformBus.h>
#include <AzFramework/Render/GeometryIntersectionStructures.h>
@@ -27,7 +28,8 @@ namespace AZ
namespace AzFramework
{
//! Implemented by components that provide bounds for use with various systems.
class BoundsRequests : public AZ::ComponentBus
class BoundsRequests
: public AZ::ComponentBus
{
public:
static void Reflect(AZ::ReflectContext* context);
@@ -37,6 +39,7 @@ namespace AzFramework
//! more than one component may be providing a bound. It isn't guaranteed which bound
//! will be returned by a single call to GetWorldBounds.
virtual AZ::Aabb GetWorldBounds() = 0;
//! Returns an axis aligned bounding box in local space.
//! @note It is preferred to use CalculateEntityLocalBoundsUnion in the general case as
//! more than one component may be providing a bound. It isn't guaranteed which bound
@@ -46,17 +49,15 @@ namespace AzFramework
protected:
~BoundsRequests() = default;
};
using BoundsRequestBus = AZ::EBus<BoundsRequests>;
//! Returns a union of all local Aabbs provided by components implementing the BoundsRequestBus.
//! @note It is preferred to call this function as opposed to GetLocalBounds directly as more than one
//! component may be implementing this bus on an Entity and so only the first result (Aabb) will be returned.
inline AZ::Aabb CalculateEntityLocalBoundsUnion(const AZ::EntityId entityId)
inline AZ::Aabb CalculateEntityLocalBoundsUnion(const AZ::Entity* entity)
{
AZ::EBusReduceResult<AZ::Aabb, AabbUnionAggregator> aabbResult(AZ::Aabb::CreateNull());
BoundsRequestBus::EventResult(
aabbResult, entityId, &BoundsRequestBus::Events::GetLocalBounds);
BoundsRequestBus::EventResult(aabbResult, entity->GetId(), &BoundsRequestBus::Events::GetLocalBounds);
if (aabbResult.value.IsValid())
{
@@ -69,18 +70,18 @@ namespace AzFramework
//! Returns a union of all world Aabbs provided by components implementing the BoundsRequestBus.
//! @note It is preferred to call this function as opposed to GetWorldBounds directly as more than one
//! component may be implementing this bus on an Entity and so only the first result (Aabb) will be returned.
inline AZ::Aabb CalculateEntityWorldBoundsUnion(const AZ::EntityId entityId)
inline AZ::Aabb CalculateEntityWorldBoundsUnion(const AZ::Entity* entity)
{
AZ::EBusReduceResult<AZ::Aabb, AabbUnionAggregator> aabbResult(AZ::Aabb::CreateNull());
BoundsRequestBus::EventResult(aabbResult, entityId, &BoundsRequestBus::Events::GetWorldBounds);
BoundsRequestBus::EventResult(aabbResult, entity->GetId(), &BoundsRequestBus::Events::GetWorldBounds);
if (aabbResult.value.IsValid())
{
return aabbResult.value;
}
AZ::Vector3 worldTranslation = AZ::Vector3::CreateZero();
AZ::TransformBus::EventResult(worldTranslation, entityId, &AZ::TransformBus::Events::GetWorldTranslation);
AZ::TransformInterface* transformInterface = entity->GetTransform();
const AZ::Vector3 worldTranslation = transformInterface->GetWorldTranslation();
return AZ::Aabb::CreateCenterHalfExtents(worldTranslation, AZ::Vector3(0.5f));
}
} // namespace AzFramework
@@ -23,9 +23,11 @@ namespace AzFramework
{
//! Provides an interface to retrieve and update the union of all Aabbs on a single Entity.
//! @note This will be the combination/union of all individual Component Aabbs.
class EntityBoundsUnionRequests : public AZ::EBusTraits
class IEntityBoundsUnion
{
public:
AZ_RTTI(IEntityBoundsUnion, "{106968DD-43C0-478E-8045-523E0BF5D0F5}");
//! Requests the cached union of component Aabbs to be recalculated as one may have changed.
//! @note This is used to drive event driven updates to the visibility system.
virtual void RefreshEntityLocalBoundsUnion(AZ::EntityId entityId) = 0;
@@ -38,9 +40,21 @@ namespace AzFramework
//! also be called explicitly (e.g. For testing purposes).
virtual void ProcessEntityBoundsUnionRequests() = 0;
//! Notifies the EntityBoundsUnion system that an entities transform has been modified.
//! @param entity the entity whose transform has been modified.
virtual void OnTransformUpdated(AZ::Entity* entity) = 0;
protected:
~EntityBoundsUnionRequests() = default;
~IEntityBoundsUnion() = default;
};
using EntityBoundsUnionRequestBus = AZ::EBus<EntityBoundsUnionRequests>;
// EBus wrapper for ScriptCanvas
class IEntityBoundsUnionTraits
: public AZ::EBusTraits
{
public:
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
};
using IEntityBoundsUnionRequestBus = AZ::EBus<IEntityBoundsUnion, IEntityBoundsUnionTraits>;
} // namespace AzFramework
@@ -17,69 +17,70 @@
namespace AzFramework
{
EntityVisibilityBoundsUnionSystem::EntityVisibilityBoundsUnionSystem()
: m_entityActivatedEventHandler([this](AZ::Entity* entity) { OnEntityActivated(entity); })
, m_entityDeactivatedEventHandler([this](AZ::Entity* entity) { OnEntityDeactivated(entity); })
{
;
}
void EntityVisibilityBoundsUnionSystem::Connect()
{
EntityBoundsUnionRequestBus::Handler::BusConnect();
AZ::TransformNotificationBus::Router::BusRouterConnect();
AZ::EntitySystemBus::Handler::BusConnect();
AZ::Interface<IEntityBoundsUnion>::Register(this);
IEntityBoundsUnionRequestBus::Handler::BusConnect();
AZ::TickBus::Handler::BusConnect();
AZ::Interface<AZ::ComponentApplicationRequests>::Get()->RegisterEntityActivatedEventHandler(m_entityActivatedEventHandler);
AZ::Interface<AZ::ComponentApplicationRequests>::Get()->RegisterEntityDeactivatedEventHandler(m_entityDeactivatedEventHandler);
}
void EntityVisibilityBoundsUnionSystem::Disconnect()
{
m_entityActivatedEventHandler.Disconnect();
m_entityDeactivatedEventHandler.Disconnect();
AZ::TickBus::Handler::BusDisconnect();
AZ::EntitySystemBus::Handler::BusDisconnect();
AZ::TransformNotificationBus::Router::BusRouterDisconnect();
EntityBoundsUnionRequestBus::Handler::BusDisconnect();
IEntityBoundsUnionRequestBus::Handler::BusDisconnect();
AZ::Interface<IEntityBoundsUnion>::Unregister(this);
}
static void SetUserDataEntityId(VisibilityEntry& visibilityEntry, const AZ::EntityId entityId)
{
static_assert(
sizeof(AZ::EntityId) <= sizeof(visibilityEntry.m_userData), "Ensure EntityId fits into m_userData");
visibilityEntry.m_typeFlags = VisibilityEntry::TYPE_Entity;
std::memcpy(&visibilityEntry.m_userData, &entityId, sizeof(AZ::EntityId));
}
void EntityVisibilityBoundsUnionSystem::OnEntityActivated(const AZ::EntityId& entityId)
void EntityVisibilityBoundsUnionSystem::OnEntityActivated(AZ::Entity* entity)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework);
// ignore any entity that might activate which does not have a TransformComponent
if (!AZ::TransformBus::HasHandlers(entityId))
if (entity->GetTransform() == nullptr)
{
return;
}
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId);
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity);
instance_it == m_entityVisibilityBoundsUnionInstanceMapping.end())
{
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM);
AZ::TransformInterface* transformInterface = entity->GetTransform();
const AZ::Vector3 entityPosition = transformInterface->GetWorldTranslation();
EntityVisibilityBoundsUnionInstance instance;
instance.m_worldTransform = worldFromLocal;
instance.m_localEntityBoundsUnion = CalculateEntityLocalBoundsUnion(entityId);
SetUserDataEntityId(instance.m_visibilityEntry, entityId);
instance.m_localEntityBoundsUnion = CalculateEntityLocalBoundsUnion(entity);
instance.m_visibilityEntry.m_typeFlags = VisibilityEntry::TYPE_Entity;
instance.m_visibilityEntry.m_userData = static_cast<void*>(entity);
auto next_it = m_entityVisibilityBoundsUnionInstanceMapping.insert({entityId, instance});
UpdateVisibilitySystem(next_it.first->second);
auto next_it = m_entityVisibilityBoundsUnionInstanceMapping.insert({ entity, instance });
UpdateVisibilitySystem(entity, next_it.first->second);
}
}
void EntityVisibilityBoundsUnionSystem::OnEntityDeactivated(const AZ::EntityId& entityId)
void EntityVisibilityBoundsUnionSystem::OnEntityDeactivated(AZ::Entity* entity)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework);
// ignore any entity that might deactivate which does not have a TransformComponent
if (!AZ::TransformBus::HasHandlers(entityId))
if (entity->GetTransform() == nullptr)
{
return;
}
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId);
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity);
instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end())
{
if (IVisibilitySystem* visibilitySystem = AZ::Interface<IVisibilitySystem>::Get())
@@ -90,7 +91,7 @@ namespace AzFramework
}
}
void EntityVisibilityBoundsUnionSystem::UpdateVisibilitySystem(EntityVisibilityBoundsUnionInstance& instance)
void EntityVisibilityBoundsUnionSystem::UpdateVisibilitySystem(AZ::Entity* entity, EntityVisibilityBoundsUnionInstance& instance)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework);
@@ -98,8 +99,8 @@ namespace AzFramework
{
// note: worldEntityBounds will not be a 'tight-fit' Aabb but that of a transformed local aabb
// there will be some wasted space but it should be sufficient for the visibility system
const AZ::Aabb worldEntityBoundsUnion =
localEntityBoundsUnions.GetTransformedAabb(instance.m_worldTransform);
AZ::TransformInterface* transformInterface = entity->GetTransform();
const AZ::Aabb worldEntityBoundsUnion = localEntityBoundsUnions.GetTransformedAabb(transformInterface->GetWorldTM());
IVisibilitySystem* visibilitySystem = AZ::Interface<IVisibilitySystem>::Get();
if (visibilitySystem && !worldEntityBoundsUnion.IsClose(instance.m_visibilityEntry.m_boundingVolume))
{
@@ -111,19 +112,27 @@ namespace AzFramework
void EntityVisibilityBoundsUnionSystem::RefreshEntityLocalBoundsUnion(const AZ::EntityId entityId)
{
// track entities that need their bounds union to be recalculated
m_entityIdsBoundsDirty.insert(entityId);
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(entityId);
if (entity != nullptr)
{
// track entities that need their bounds union to be recalculated
m_entityBoundsDirty.insert(entity);
}
}
AZ::Aabb EntityVisibilityBoundsUnionSystem::GetEntityLocalBoundsUnion(const AZ::EntityId entityId) const
{
// if the EntityId is not found in the mapping then return a null Aabb, this is to mimic
// as closely as possible the behavior of an individual GetLocalBounds call to an Entity that
// had been deleted (there would be no response, leaving the default value assigned)
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId);
instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end())
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(entityId);
if (entity != nullptr)
{
return instance_it->second.m_localEntityBoundsUnion;
// if the entity is not found in the mapping then return a null Aabb, this is to mimic
// as closely as possible the behavior of an individual GetLocalBounds call to an Entity that
// had been deleted (there would be no response, leaving the default value assigned)
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity);
instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end())
{
return instance_it->second.m_localEntityBoundsUnion;
}
}
return AZ::Aabb::CreateNull();
@@ -134,45 +143,29 @@ namespace AzFramework
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework);
// iterate over all entities whose bounds changed and recalculate them
for (const auto& entityId : m_entityIdsBoundsDirty)
for (const auto& entity : m_entityBoundsDirty)
{
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId);
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity);
instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end())
{
instance_it->second.m_localEntityBoundsUnion = CalculateEntityLocalBoundsUnion(entityId);
}
}
auto allDirtyEntityIds = m_entityIdsTransformDirty;
allDirtyEntityIds.insert(m_entityIdsBoundsDirty.begin(), m_entityIdsBoundsDirty.end());
for (const auto& dirtyEntityId : allDirtyEntityIds)
{
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(dirtyEntityId);
instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end())
{
UpdateVisibilitySystem(instance_it->second);
instance_it->second.m_localEntityBoundsUnion = CalculateEntityLocalBoundsUnion(entity);
UpdateVisibilitySystem(entity, instance_it->second);
}
}
// clear dirty entities once the visibility system has been updated
m_entityIdsBoundsDirty.clear();
m_entityIdsTransformDirty.clear();
m_entityBoundsDirty.clear();
}
void EntityVisibilityBoundsUnionSystem::OnTransformChanged(
[[maybe_unused]] const AZ::Transform& local, const AZ::Transform& world)
void EntityVisibilityBoundsUnionSystem::OnTransformUpdated(AZ::Entity* entity)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework);
const AZ::EntityId entityId = *AZ::TransformNotificationBus::GetCurrentBusId();
m_entityIdsTransformDirty.insert(entityId);
// update the world transform of the visibility bounds union
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId);
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity);
instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end())
{
instance_it->second.m_worldTransform = world;
UpdateVisibilitySystem(entity, instance_it->second);
}
}
@@ -23,12 +23,12 @@ namespace AzFramework
{
//! Provide a unified hook between entities and the visibility system.
class EntityVisibilityBoundsUnionSystem
: public EntityBoundsUnionRequestBus::Handler
, private AZ::EntitySystemBus::Handler
, private AZ::TransformNotificationBus::Router
: public IEntityBoundsUnionRequestBus::Handler
, private AZ::TickBus::Handler
{
public:
EntityVisibilityBoundsUnionSystem();
void Connect();
void Disconnect();
@@ -36,34 +36,31 @@ namespace AzFramework
void RefreshEntityLocalBoundsUnion(AZ::EntityId entityId) override;
AZ::Aabb GetEntityLocalBoundsUnion(AZ::EntityId entityId) const override;
void ProcessEntityBoundsUnionRequests() override;
void OnTransformUpdated(AZ::Entity* entity) override;
private:
struct EntityVisibilityBoundsUnionInstance
{
AZ::Transform m_worldTransform = AZ::Transform::CreateIdentity(); //!< The world transform of the Entity.
AZ::Aabb m_localEntityBoundsUnion =
AZ::Aabb::CreateNull(); //!< Entity union bounding volume in local space.
AZ::Aabb m_localEntityBoundsUnion = AZ::Aabb::CreateNull(); //!< Entity union bounding volume in local space.
VisibilityEntry m_visibilityEntry; //!< Hook into the IVisibilitySystem interface.
};
using UniqueEntityIds = AZStd::unordered_set<AZ::EntityId>;
using UniqueEntities = AZStd::set<AZ::Entity*>;
using EntityVisibilityBoundsUnionInstanceMapping =
AZStd::unordered_map<AZ::EntityId, EntityVisibilityBoundsUnionInstance>;
AZStd::unordered_map<AZ::Entity*, EntityVisibilityBoundsUnionInstance>;
void OnEntityActivated(AZ::Entity* entity);
void OnEntityDeactivated(AZ::Entity* entity);
// TickBus overrides ...
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
// EntitySystemBus overrides ...
void OnEntityActivated(const AZ::EntityId& entityId) override;
void OnEntityDeactivated(const AZ::EntityId& entityId) override;
// TransformNotificationBus overrides ...
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
void UpdateVisibilitySystem(EntityVisibilityBoundsUnionInstance& instance);
void UpdateVisibilitySystem(AZ::Entity* entity, EntityVisibilityBoundsUnionInstance& instance);
EntityVisibilityBoundsUnionInstanceMapping m_entityVisibilityBoundsUnionInstanceMapping;
UniqueEntityIds m_entityIdsBoundsDirty;
UniqueEntityIds m_entityIdsTransformDirty;
UniqueEntities m_entityBoundsDirty;
AZ::EntityActivatedEvent::Handler m_entityActivatedEventHandler;
AZ::EntityDeactivatedEvent::Handler m_entityDeactivatedEventHandler;
};
} // namespace AzFramework
@@ -14,6 +14,7 @@
#include <AzCore/Console/Console.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Math/ShapeIntersection.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzFramework/Visibility/IVisibilitySystem.h>
@@ -66,6 +67,7 @@ namespace AzFramework
octreeDebug.m_nodeBounds.push_back(nodeData.m_bounds);
}
visibleEntityIdsOut.reserve(visibleEntityIdsOut.size() + nodeData.m_entries.size());
for (const auto* visibilityEntry : nodeData.m_entries)
{
if (ed_visibility_showDebug)
@@ -88,8 +90,7 @@ namespace AzFramework
octreeDebug.m_entryAabbsInFrustum.push_back(visibilityEntry->m_boundingVolume);
}
AZ::EntityId entityId;
std::memcpy(&entityId, &visibilityEntry->m_userData, sizeof(AZ::EntityId));
AZ::EntityId entityId = static_cast<AZ::Entity*>(visibilityEntry->m_userData)->GetId();
visibleEntityIdsOut.push_back(entityId);
}
});
@@ -13,4 +13,3 @@
#pragma once
#define STREAM_CACHE_DEFAULT 0
#define FRONTEND_SHADER_CACHE_DEFAULT 0
@@ -13,4 +13,3 @@
#pragma once
#define STREAM_CACHE_DEFAULT 0
#define FRONTEND_SHADER_CACHE_DEFAULT 0
@@ -13,4 +13,3 @@
#pragma once
#define STREAM_CACHE_DEFAULT 0
#define FRONTEND_SHADER_CACHE_DEFAULT 0
@@ -13,4 +13,3 @@
#pragma once
#define STREAM_CACHE_DEFAULT 0
#define FRONTEND_SHADER_CACHE_DEFAULT 0
@@ -13,4 +13,3 @@
#pragma once
#define STREAM_CACHE_DEFAULT 0
#define FRONTEND_SHADER_CACHE_DEFAULT 0
@@ -19,9 +19,10 @@ namespace AzNetworking
static const int32_t FloatHashMinValue = (INT_MIN >> 7);
static const int32_t FloatHashMaxValue = (INT_MAX >> 7);
AZ::HashValue64 HashSerializer::GetHash() const
AZ::HashValue32 HashSerializer::GetHash() const
{
return m_hash;
// Just truncate the upper bits
return static_cast<AZ::HashValue32>(m_hash);
}
SerializerMode HashSerializer::GetSerializerMode() const
@@ -27,7 +27,7 @@ namespace AzNetworking
HashSerializer() = default;
AZ::HashValue64 GetHash() const;
AZ::HashValue32 GetHash() const;
// ISerializer interfaces
SerializerMode GetSerializerMode() const override;
@@ -0,0 +1,162 @@
/*
* 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 <AzNetworking/Serialization/StringifySerializer.h>
namespace AzNetworking
{
StringifySerializer::StringifySerializer(char delimeter, bool outputFieldNames, const AZStd::string& seperator)
: m_delimeter(delimeter)
, m_outputFieldNames(outputFieldNames)
, m_separator(seperator)
{
;
}
const AZStd::string& StringifySerializer::GetString() const
{
return m_string;
}
const StringifySerializer::StringMap& StringifySerializer::GetValueMap() const
{
return m_map;
}
SerializerMode StringifySerializer::GetSerializerMode() const
{
return SerializerMode::ReadFromObject;
}
bool StringifySerializer::Serialize(bool& value, const char* name)
{
return ProcessData(name, value);
}
bool StringifySerializer::Serialize(char& value, const char* name, char, char)
{
const int val = value; // Print chars as integers
return ProcessData(name, val);
}
bool StringifySerializer::Serialize(int8_t& value, const char* name, int8_t, int8_t)
{
return ProcessData(name, value);
}
bool StringifySerializer::Serialize(int16_t& value, const char* name, int16_t, int16_t)
{
return ProcessData(name, value);
}
bool StringifySerializer::Serialize(int32_t& value, const char* name, int32_t, int32_t)
{
return ProcessData(name, value);
}
bool StringifySerializer::Serialize(int64_t& value, const char* name, int64_t, int64_t)
{
return ProcessData(name, value);
}
bool StringifySerializer::Serialize(uint8_t& value, const char* name, uint8_t, uint8_t)
{
return ProcessData(name, value);
}
bool StringifySerializer::Serialize(uint16_t& value, const char* name, uint16_t, uint16_t)
{
return ProcessData(name, value);
}
bool StringifySerializer::Serialize(uint32_t& value, const char* name, uint32_t, uint32_t)
{
return ProcessData(name, value);
}
bool StringifySerializer::Serialize(uint64_t& value, const char* name, uint64_t, uint64_t)
{
return ProcessData(name, value);
}
bool StringifySerializer::Serialize(float& value, const char* name, float, float)
{
return ProcessData(name, value);
}
bool StringifySerializer::Serialize(double& value, const char* name, double, double)
{
return ProcessData(name, value);
}
bool StringifySerializer::SerializeBytes(uint8_t* buffer, uint32_t, bool isString, uint32_t&, const char* name)
{
if (isString)
{
AZ::CVarFixedString value = reinterpret_cast<char*>(buffer);
return ProcessData(name, value);
}
return false;
}
bool StringifySerializer::BeginObject(const char* name, const char*)
{
m_prefixSizeStack.push_back(m_prefix.size());
m_prefix += name;
m_prefix += ".";
return true;
}
bool StringifySerializer::EndObject(const char*, const char*)
{
m_prefix.resize(m_prefixSizeStack.back());
m_prefixSizeStack.pop_back();
return true;
}
const uint8_t* StringifySerializer::GetBuffer() const
{
return nullptr;
}
uint32_t StringifySerializer::GetCapacity() const
{
return 0;
}
uint32_t StringifySerializer::GetSize() const
{
return 0;
}
template <typename T>
bool StringifySerializer::ProcessData(const char* name, const T& value)
{
// Only add delimeters after we have processed at least one element
if (!m_string.empty())
{
m_string += m_delimeter;
}
if (m_outputFieldNames)
{
m_string += m_prefix;
m_string += name;
m_string += m_separator;
}
AZ::CVarFixedString string = AZ::ConsoleTypeHelpers::ValueToString(value);
m_string += string.c_str();
m_map[m_prefix + name] = string.c_str();
return true;
}
}
@@ -0,0 +1,80 @@
/*
* 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 <AzNetworking/Serialization/ISerializer.h>
#include <AzCore/std/containers/map.h>
namespace AzNetworking
{
// StringifySerializer
// Generate a debug string of a serializable object
class StringifySerializer
: public ISerializer
{
public:
using StringMap = AZStd::map<AZStd::string, AZStd::string>;
StringifySerializer(char delimeter = ' ', bool outputFieldNames = true, const AZStd::string& seperator = "=");
// GetString
// After serializing objects, get the serialized values as a single string
const AZStd::string& GetString() const;
// GetValueMap
// After serializing objects, get the serialized values as key value pairs
const StringMap& GetValueMap() const;
// ISerializer interfaces
SerializerMode GetSerializerMode() const override;
bool Serialize(bool& value, const char* name) override;
bool Serialize(char& value, const char* name, char minValue, char maxValue) override;
bool Serialize(int8_t& value, const char* name, int8_t minValue, int8_t maxValue) override;
bool Serialize(int16_t& value, const char* name, int16_t minValue, int16_t maxValue) override;
bool Serialize(int32_t& value, const char* name, int32_t minValue, int32_t maxValue) override;
bool Serialize(int64_t& value, const char* name, int64_t minValue, int64_t maxValue) override;
bool Serialize(uint8_t& value, const char* name, uint8_t minValue, uint8_t maxValue) override;
bool Serialize(uint16_t& value, const char* name, uint16_t minValue, uint16_t maxValue) override;
bool Serialize(uint32_t& value, const char* name, uint32_t minValue, uint32_t maxValue) override;
bool Serialize(uint64_t& value, const char* name, uint64_t minValue, uint64_t maxValue) override;
bool Serialize(float& value, const char* name, float minValue, float maxValue) override;
bool Serialize(double& value, const char* name, double minValue, double maxValue) override;
bool SerializeBytes(uint8_t* buffer, uint32_t bufferCapacity, bool isString, uint32_t& outSize, const char* name) override;
bool BeginObject(const char* name, const char* typeName) override;
bool EndObject(const char* name, const char* typeName) override;
const uint8_t* GetBuffer() const override;
uint32_t GetCapacity() const override;
uint32_t GetSize() const override;
void ClearTrackedChangesFlag() override {}
bool GetTrackedChangesFlag() const override { return false; }
// ISerializer interfaces
private:
template <typename T>
bool ProcessData(const char* name, const T& value);
private:
char m_delimeter;
bool m_outputFieldNames = true;
StringMap m_map;
AZStd::string m_string;
AZStd::string m_prefix;
AZStd::string m_separator;
AZStd::deque<AZStd::size_t> m_prefixSizeStack;
};
}
@@ -65,6 +65,8 @@ set(FILES
Serialization/NetworkOutputSerializer.cpp
Serialization/NetworkOutputSerializer.h
Serialization/NetworkOutputSerializer.inl
Serialization/StringifySerializer.cpp
Serialization/StringifySerializer.h
Serialization/TrackChangedSerializer.h
Serialization/TrackChangedSerializer.inl
TcpTransport/TcpConnection.cpp
@@ -180,6 +180,8 @@ namespace AzQtComponents
textSearch->setFrame(false);
textSearch->setText(QString());
textSearch->setPlaceholderText(QObject::tr("Search..."));
textSearch->setClearButtonEnabled(true);
LineEdit::applySearchStyle(textSearch);
connect(textSearch, &QLineEdit::textChanged, this, &SearchTypeSelector::FilterTextChanged);
m_searchLayout->addWidget(textSearch);
@@ -31,6 +31,10 @@ namespace AzToolsFramework
//! Allows a component to get the list of selected entities
//! \param selectedEntityIds the return vector holding the entities required
virtual void GetSelectedEntities(EntityIdList& selectedEntityIds) = 0;
//! Explicitly sets a component as having been the most recently added.
//! This means that the next time the UI refreshes, that component will be ensured to be visible.
virtual void SetNewComponentId(AZ::ComponentId componentId) = 0;
};
using EntityPropertyEditorRequestBus = AZ::EBus<EntityPropertyEditorRequests>;
@@ -761,16 +761,6 @@ namespace AzToolsFramework
/// If the view pane was not registered with the ViewPaneOptions.isDeletable set to true, the view pane will be hidden instead.
virtual void CloseViewPane(const char* /*paneName*/) {}
/// Request generation of all level cubemaps.
virtual void GenerateAllCubemaps() {}
/// Regenerate cubemap for a particular entity.
/// \param entityId ID of the entity that the cubemap is for
/// \param cubemapOutputPath path to a image file to generate
/// \param hideEntity Indicates whether the entity should be hidden during cubemap generation. Controls whether the entity's current cubemap output is baked into the new cubemap.
virtual void GenerateCubemapForEntity(AZ::EntityId /*entityId*/, AZStd::string* /*cubemapOutputPath*/, bool /*hideEntity*/) {}
virtual void GenerateCubemapWithIDForEntity(AZ::EntityId /*entityId*/, AZ::Uuid /*cubemapId*/, AZStd::string* /*cubemapOutputPath*/, bool /*hideEntity*/, bool /*hasCubemapId*/) {}
//! Spawn asset browser for the appropriate asset types.
virtual void BrowseForAssets(AssetBrowser::AssetSelectionModel& /*selection*/) = 0;
@@ -189,9 +189,6 @@ namespace AzToolsFramework
SliceEditorEntityOwnershipServiceNotificationBus::Handler::BusConnect();
EditorLegacyGameModeNotificationBus::Handler::BusConnect();
m_entityVisibilityBoundsUnionSystem.Connect();
}
//=========================================================================
@@ -199,8 +196,6 @@ namespace AzToolsFramework
//=========================================================================
void EditorEntityContextComponent::Deactivate()
{
m_entityVisibilityBoundsUnionSystem.Disconnect();
EditorLegacyGameModeNotificationBus::Handler::BusDisconnect();
SliceEditorEntityOwnershipServiceNotificationBus::Handler::BusDisconnect();
@@ -189,8 +189,6 @@ namespace AzToolsFramework
//! EditorEntityContextRequestBus::Events::AddRequiredComponents()
AZ::ComponentTypeList m_requiredEditorComponentTypes;
//! Edit time visibility management integrating entities with the IVisibilitySystem.
AzFramework::EntityVisibilityBoundsUnionSystem m_entityVisibilityBoundsUnionSystem;
bool m_isLegacySliceService;
UndoSystem::UndoCacheInterface* m_undoCacheInterface = nullptr;
@@ -85,14 +85,14 @@ namespace AzToolsFramework
// if we're snapping, only increment current radians when we know
// preSnapRadians is greater than the angleStep
if (snapping)
if (snapping && AZStd::abs(angleStepDegrees) > 0.0f)
{
actionInternal.m_current.m_preSnapRadians += rotationAngleRad * rotateSign;
const float angleStepRad = AZ::DegToRad(angleStepDegrees);
const float preSnapRotateSign = Sign(actionInternal.m_current.m_preSnapRadians);
// if we move more than angleStep in a frame, make sure we catch up
while (fabsf(actionInternal.m_current.m_preSnapRadians) >= angleStepRad)
while (AZStd::abs(actionInternal.m_current.m_preSnapRadians) >= angleStepRad)
{
actionInternal.m_current.m_radians += angleStepRad * preSnapRotateSign;
actionInternal.m_current.m_preSnapRadians -= angleStepRad * preSnapRotateSign;
@@ -182,6 +182,22 @@ namespace AzToolsFramework
instanceToParentUnder = prefabEditorEntityOwnershipInterface->GetRootPrefabInstance();
parent = instanceToParentUnder->get().GetContainerEntityId();
}
//Detect whether this instantiation would produce a cyclical dependency
auto relativePath = m_prefabLoaderInterface->GetRelativePathToProject(filePath);
Prefab::TemplateId templateId = m_prefabSystemComponentInterface->GetTemplateIdFromFilePath(relativePath);
// If the template isn't currently loaded, there's no way for it to be in the hierarchy so we just skip the check.
if (templateId != Prefab::InvalidTemplateId && IsPrefabInInstanceAncestorHierarchy(templateId, instanceToParentUnder->get()))
{
return AZ::Failure(
AZStd::string::format(
"Instantiate Prefab operation aborted - Cyclical dependency detected\n(%s depends on %s).",
relativePath.Native().c_str(),
instanceToParentUnder->get().GetTemplateSourcePath().Native().c_str()
)
);
}
{
// Initialize Undo Batch object
@@ -192,7 +208,7 @@ namespace AzToolsFramework
instanceToParentUnderDomBeforeCreate, instanceToParentUnder->get());
// Instantiate the Prefab
auto instanceToCreate = prefabEditorEntityOwnershipInterface->InstantiatePrefab(filePath, instanceToParentUnder);
auto instanceToCreate = prefabEditorEntityOwnershipInterface->InstantiatePrefab(relativePath, instanceToParentUnder);
if (!instanceToCreate)
{
@@ -242,6 +258,23 @@ namespace AzToolsFramework
return AZ::Success();
}
bool PrefabPublicHandler::IsPrefabInInstanceAncestorHierarchy(TemplateId prefabTemplateId, InstanceOptionalConstReference instance)
{
InstanceOptionalConstReference currentInstance = instance;
while (currentInstance.has_value())
{
if (currentInstance->get().GetTemplateId() == prefabTemplateId)
{
return true;
}
currentInstance = currentInstance->get().GetParentInstance();
}
return false;
}
void PrefabPublicHandler::CreateLink(
const EntityList& topLevelEntities, Instance& sourceInstance, TemplateId targetTemplateId,
UndoSystem::URSequencePoint* undoBatch, AZ::EntityId commonRootEntityId)
@@ -106,6 +106,14 @@ namespace AzToolsFramework
const AZStd::vector<AZ::EntityId>& entityIds, EntityList& inputEntityList, EntityList& topLevelEntities,
AZ::EntityId& commonRootEntityId, InstanceOptionalReference& commonRootEntityOwningInstance);
/* Detects whether an instance of prefabTemplateId is present in the hierarchy of ancestors of instance.
*
* \param prefabTemplateId The template id to test for
* \param instance The instance whose ancestor hierarchy prefabTemplateId will be tested against.
* \return true if an instance of the template of id prefabTemplateId could be found in the ancestor hierarchy of instance, false otherwise.
*/
bool IsPrefabInInstanceAncestorHierarchy(TemplateId prefabTemplateId, InstanceOptionalConstReference instance);
static Instance* GetParentInstance(Instance* instance);
static Instance* GetAncestorOfInstanceThatIsChildOfRoot(const Instance* ancestor, Instance* descendant);
static void GenerateContainerEntityTransform(const EntityList& topLevelEntities, AZ::Vector3& translation, AZ::Quaternion& rotation);
@@ -721,6 +721,8 @@ namespace AzToolsFramework
TemplateId PrefabSystemComponent::GetTemplateIdFromFilePath(AZ::IO::PathView filePath) const
{
AZ_Assert(!filePath.IsAbsolute(), "Prefab - GetTemplateIdFromFilePath was passed an absolute path. Prefabs use paths relative to the project folder.");
auto found = m_templateFilePathToIdMap.find(filePath);
if (found != m_templateFilePathToIdMap.end())
{
@@ -39,9 +39,10 @@ namespace AzToolsFramework
editContext->Class<EditorNonUniformScaleComponent>("Non-uniform Scale",
"Non-uniform scale for this entity only (does not propagate through hierarchy)")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "Non-uniform Scale")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::FixedComponentListIndex, 1)
->Attribute(AZ::Edit::Attributes::RemoveableByUser, true)
->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/NonUniformScale.svg")
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/NonUniformScale.svg")
->DataElement(
AZ::Edit::UIHandlers::Default, &EditorNonUniformScaleComponent::m_scale, "Non-uniform Scale",
"Non-uniform scale for this entity only (does not propagate through hierarchy)")
@@ -61,6 +62,8 @@ namespace AzToolsFramework
void EditorNonUniformScaleComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC_CE("NonUniformScaleService"));
incompatible.push_back(AZ_CRC_CE("DebugDrawObbService"));
incompatible.push_back(AZ_CRC_CE("DebugDrawService"));
incompatible.push_back(AZ_CRC_CE("EMotionFXActorService"));
@@ -25,11 +25,16 @@
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzFramework/Components/TransformComponent.h>
#include <AzFramework/Visibility/EntityBoundsUnionBus.h>
#include <AzToolsFramework/API/EntityCompositionRequestBus.h>
#include <AzToolsFramework/API/EntityPropertyEditorRequestsBus.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
#include <AzToolsFramework/ToolsComponents/TransformComponentBus.h>
#include <AzToolsFramework/ToolsComponents/TransformScalePropertyHandler.h>
#include <AzToolsFramework/ToolsComponents/EditorInspectorComponentBus.h>
#include <AzToolsFramework/ToolsComponents/EditorPendingCompositionBus.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
@@ -261,6 +266,13 @@ namespace AzToolsFramework
AZ::TransformNotificationBus::Event(
GetEntityId(), &TransformNotification::OnTransformChanged, localTM, worldTM);
m_transformChangedEvent.Signal(localTM, worldTM);
AzFramework::IEntityBoundsUnion* boundsUnion = AZ::Interface<AzFramework::IEntityBoundsUnion>::Get();
if (boundsUnion != nullptr)
{
boundsUnion->OnTransformUpdated(GetEntity());
}
}
}
@@ -929,15 +941,14 @@ namespace AzToolsFramework
{
return nullptr;
}
AZ::Entity* pEntity = nullptr;
EBUS_EVENT_RESULT(pEntity, AZ::ComponentApplicationBus, FindEntity, otherEntityId);
if (!pEntity)
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(otherEntityId);
if (!entity)
{
return nullptr;
}
return pEntity->FindComponent<TransformComponent>();
return entity->FindComponent<TransformComponent>();
}
AZ::TransformInterface* TransformComponent::GetParent()
@@ -1196,6 +1207,66 @@ namespace AzToolsFramework
destinationComponent->SetWorldTM(const_cast<TransformComponent*>(sourceComponent)->GetWorldTM());
}
AZ::Component* TransformComponent::FindPresentOrPendingComponent(AZ::Uuid componentUuid)
{
// first check if the component is present and valid
if (AZ::Component* foundComponent = GetEntity()->FindComponent(componentUuid))
{
return foundComponent;
}
// then check to see if there's a component pending because it's in an invalid state
AZStd::vector<AZ::Component*> pendingComponents;
AzToolsFramework::EditorPendingCompositionRequestBus::Event(GetEntityId(),
&AzToolsFramework::EditorPendingCompositionRequests::GetPendingComponents, pendingComponents);
for (const auto pendingComponent : pendingComponents)
{
if (pendingComponent->RTTI_IsTypeOf(componentUuid))
{
return pendingComponent;
}
}
return nullptr;
}
bool TransformComponent::IsAddNonUniformScaleButtonReadOnly()
{
return FindPresentOrPendingComponent(EditorNonUniformScaleComponent::TYPEINFO_Uuid()) != nullptr;
}
AZ::Crc32 TransformComponent::OnAddNonUniformScaleButtonPressed()
{
// if there is already a non-uniform scale component, do nothing
if (FindPresentOrPendingComponent(EditorNonUniformScaleComponent::TYPEINFO_Uuid()))
{
return AZ::Edit::PropertyRefreshLevels::None;
}
const AZStd::vector<AZ::EntityId> entityList = { GetEntityId() };
const AZ::ComponentTypeList componentsToAdd = { EditorNonUniformScaleComponent::TYPEINFO_Uuid() };
AzToolsFramework::EntityCompositionRequests::AddComponentsOutcome addComponentsOutcome;
AzToolsFramework::EntityCompositionRequestBus::BroadcastResult(addComponentsOutcome,
&AzToolsFramework::EntityCompositionRequests::AddComponentsToEntities, entityList, componentsToAdd);
const auto nonUniformScaleComponent = FindPresentOrPendingComponent(EditorNonUniformScaleComponent::RTTI_Type());
AZ::ComponentId nonUniformScaleComponentId =
nonUniformScaleComponent ? nonUniformScaleComponent->GetId() : AZ::InvalidComponentId;
if (!addComponentsOutcome.IsSuccess() || !nonUniformScaleComponent)
{
AZ_Warning("Transform component", false, "Failed to add non-uniform scale component.");
return AZ::Edit::PropertyRefreshLevels::None;
}
AzToolsFramework::EntityPropertyEditorRequestBus::Broadcast(
&AzToolsFramework::EntityPropertyEditorRequests::SetNewComponentId, nonUniformScaleComponentId);
return AZ::Edit::PropertyRefreshLevels::EntireTree;
}
void TransformComponent::Reflect(AZ::ReflectContext* context)
{
// reflect data for script, serialization, editing..
@@ -1211,6 +1282,7 @@ namespace AzToolsFramework
serializeContext->Class<Components::TransformComponent, EditorComponentBase>()->
Field("Parent Entity", &TransformComponent::m_parentEntityId)->
Field("Transform Data", &TransformComponent::m_editorTransform)->
Field("AddNonUniformScaleButton", &TransformComponent::m_addNonUniformScaleButton)->
Field("Cached World Transform", &TransformComponent::m_cachedWorldTransform)->
Field("Cached World Transform Parent", &TransformComponent::m_cachedWorldTransformParent)->
Field("Parent Activation Transform Mode", &TransformComponent::m_parentActivationTransformMode)->
@@ -1224,6 +1296,7 @@ namespace AzToolsFramework
{
ptrEdit->Class<TransformComponent>("Transform", "Controls the placement of the entity in the world in 3d")->
ClassElement(AZ::Edit::ClassElements::EditorData, "")->
Attribute(AZ::Edit::Attributes::FixedComponentListIndex, 0)->
Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Transform.svg")->
Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Transform.png")->
Attribute(AZ::Edit::Attributes::AutoExpand, true)->
@@ -1234,6 +1307,10 @@ namespace AzToolsFramework
DataElement(AZ::Edit::UIHandlers::Default, &TransformComponent::m_editorTransform, "Values", "")->
Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::TransformChanged)->
Attribute(AZ::Edit::Attributes::AutoExpand, true)->
DataElement(AZ::Edit::UIHandlers::Button, &TransformComponent::m_addNonUniformScaleButton, "", "")->
Attribute(AZ::Edit::Attributes::ButtonText, "Add non-uniform scale")->
Attribute(AZ::Edit::Attributes::ReadOnly, &TransformComponent::IsAddNonUniformScaleButtonReadOnly)->
Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::OnAddNonUniformScaleButtonPressed)->
DataElement(AZ::Edit::UIHandlers::ComboBox, &TransformComponent::m_parentActivationTransformMode,
"Parent activation", "Configures relative transform behavior when parent activates.")->
EnumAttribute(AZ::TransformConfig::ParentActivationTransformMode::MaintainOriginalRelativeTransform, "Original relative transform")->
@@ -23,6 +23,7 @@
#include <AzToolsFramework/API/ComponentEntitySelectionBus.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/Commands/SelectionCommand.h>
#include <AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.h>
#include "EditorComponentBase.h"
#include "TransformComponentBus.h"
@@ -228,6 +229,10 @@ namespace AzToolsFramework
void CheckApplyCachedWorldTransform(const AZ::Transform& parentWorld);
AZ::Component* FindPresentOrPendingComponent(AZ::Uuid componentUuid);
bool IsAddNonUniformScaleButtonReadOnly();
AZ::Crc32 OnAddNonUniformScaleButtonPressed();
// Drives transform behavior when parent activates. See AZ::TransformConfig::ParentActivationTransformMode for details.
AZ::TransformConfig::ParentActivationTransformMode m_parentActivationTransformMode;
@@ -260,6 +265,10 @@ namespace AzToolsFramework
bool m_worldTransformDirty = true;
bool m_isStatic = false;
// This is a workaround for a bug which causes the button to appear with incorrect placement if a UI
// element is used rather than a data element.
bool m_addNonUniformScaleButton = false;
// Deprecated
AZ::InterpolationMode m_interpolatePosition;
AZ::InterpolationMode m_interpolateRotation;
@@ -63,6 +63,7 @@ AZ_POP_DISABLE_WARNING
#include <AzToolsFramework/ToolsComponents/EditorOnlyEntityComponentBus.h>
#include <AzToolsFramework/ToolsComponents/EditorOnlyEntityComponent.h>
#include <AzToolsFramework/ToolsComponents/EditorLayerComponent.h>
#include <AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.h>
#include <AzToolsFramework/ToolsMessaging/EntityHighlightBus.h>
#include <AzToolsFramework/UI/ComponentPalette/ComponentPaletteUtil.hxx>
#include <AzToolsFramework/UI/ComponentPalette/ComponentPaletteWidget.hxx>
@@ -334,6 +335,7 @@ namespace AzToolsFramework
m_gui->m_entityDetailsLabel->setObjectName("LabelEntityDetails");
m_gui->m_entitySearchBox->setReadOnly(false);
m_gui->m_entitySearchBox->setContextMenuPolicy(Qt::CustomContextMenu);
m_gui->m_entitySearchBox->setClearButtonEnabled(true);
AzQtComponents::LineEdit::applySearchStyle(m_gui->m_entitySearchBox);
AzFramework::ApplicationRequests::Bus::BroadcastResult(
@@ -494,6 +496,11 @@ namespace AzToolsFramework
}
}
void EntityPropertyEditor::SetNewComponentId(AZ::ComponentId componentId)
{
m_newComponentId = componentId;
}
void EntityPropertyEditor::SetOverrideEntityIds(const AzToolsFramework::EntityIdSet& entities)
{
m_overrideSelectedEntityIds = entities;
@@ -1039,15 +1046,23 @@ namespace AzToolsFramework
sortedComponents.end(),
[=](const OrderedSortComponentEntry& component1, const OrderedSortComponentEntry& component2)
{
// Transform component must be first, always
// If component 1 is a transform component, it is sorted earlier
if (component1.m_component->RTTI_IsTypeOf(AZ::EditorTransformComponentTypeId))
AZStd::optional<int> fixedComponentListIndex1 = GetFixedComponentListIndex(component1.m_component);
AZStd::optional<int> fixedComponentListIndex2 = GetFixedComponentListIndex(component2.m_component);
// If both components have fixed list indices, sort based on those indices
if (fixedComponentListIndex1.has_value() && fixedComponentListIndex2.has_value())
{
return fixedComponentListIndex1.value() < fixedComponentListIndex2.value();
}
// If component 1 has a fixed list index, sort it first
if (fixedComponentListIndex1.has_value())
{
return true;
}
// If component 2 is a transform component, component 1 is never sorted earlier
if (component2.m_component->RTTI_IsTypeOf(AZ::EditorTransformComponentTypeId))
// If component 2 has a fixed list index, component 1 should not be sorted before it
if (fixedComponentListIndex2.has_value())
{
return false;
}
@@ -1128,10 +1143,7 @@ namespace AzToolsFramework
{
if (auto attributeData = azdynamic_cast<AZ::Edit::AttributeData<bool>*>(attribute))
{
if (!attributeData->Get(nullptr))
{
return false;
}
return attributeData->Get(nullptr);
}
}
}
@@ -1166,6 +1178,36 @@ namespace AzToolsFramework
return true;
}
AZStd::optional<int> EntityPropertyEditor::GetFixedComponentListIndex(const AZ::Component* component)
{
auto componentClassData = component ? GetComponentClassData(component) : nullptr;
if (componentClassData && componentClassData->m_editData)
{
if (auto editorDataElement = componentClassData->m_editData->FindElementData(AZ::Edit::ClassElements::EditorData))
{
if (auto attribute = editorDataElement->FindAttribute(AZ::Edit::Attributes::FixedComponentListIndex))
{
if (auto attributeData = azdynamic_cast<AZ::Edit::AttributeData<int>*>(attribute))
{
return { attributeData->Get(nullptr) };
}
}
}
}
return {};
}
bool EntityPropertyEditor::IsComponentDraggable(const AZ::Component* component)
{
return !GetFixedComponentListIndex(component).has_value();
}
bool EntityPropertyEditor::AreComponentsDraggable(const AZ::Entity::ComponentArrayType& components) const
{
return AZStd::all_of(
components.begin(), components.end(), [](AZ::Component* component) { return IsComponentDraggable(component); });
}
bool EntityPropertyEditor::AreComponentsCopyable(const AZ::Entity::ComponentArrayType& components) const
{
return AreComponentsCopyable(components, m_componentFilter);
@@ -3367,7 +3409,9 @@ namespace AzToolsFramework
sourceComponents.size() == m_selectedEntityIds.size() &&
targetComponents.size() == m_selectedEntityIds.size() &&
AreComponentsRemovable(sourceComponents) &&
AreComponentsRemovable(targetComponents);
AreComponentsRemovable(targetComponents) &&
AreComponentsDraggable(sourceComponents) &&
AreComponentsDraggable(targetComponents);
}
bool EntityPropertyEditor::IsMoveComponentsUpAllowed() const
@@ -3681,14 +3725,38 @@ namespace AzToolsFramework
void EntityPropertyEditor::ScrollToNewComponent()
{
//force new components to be visible, assuming they are added to the end of the list and layout
auto componentEditor = GetComponentEditorsFromIndex(m_componentEditorsUsed - 1);
// force new components to be visible
// if no component has been explicitly set at the most recently added,
// assume new components are added to the end of the list and layout
AZ::s32 newComponentIndex = m_componentEditorsUsed - 1;
// if there is a component id explicitly set as the most recently added, try to find it and make sure it is visible
if (m_newComponentId.has_value() && m_newComponentId.value() != AZ::InvalidComponentId)
{
AZ::ComponentId newComponentId = m_newComponentId.value();
for (AZ::s32 componentIndex = 0; componentIndex < m_componentEditorsUsed; ++componentIndex)
{
if (m_componentEditors[componentIndex])
{
for (const auto component : m_componentEditors[componentIndex]->GetComponents())
{
if (component->GetId() == newComponentId)
{
newComponentIndex = componentIndex;
}
}
}
}
}
auto componentEditor = GetComponentEditorsFromIndex(newComponentIndex);
if (componentEditor)
{
m_gui->m_componentList->ensureWidgetVisible(componentEditor);
}
m_shouldScrollToNewComponents = false;
m_shouldScrollToNewComponentsQueued = false;
m_newComponentId.reset();
}
void EntityPropertyEditor::QueueScrollToNewComponent()
@@ -4073,7 +4141,8 @@ namespace AzToolsFramework
{
if (!componentEditor ||
!componentEditor->isVisible() ||
!AreComponentsRemovable(componentEditor->GetComponents()))
!AreComponentsRemovable(componentEditor->GetComponents()) ||
!AreComponentsDraggable(componentEditor->GetComponents()))
{
return false;
}
@@ -4223,6 +4292,7 @@ namespace AzToolsFramework
while (targetComponentEditor
&& (targetComponentEditor->IsDragged()
|| !AreComponentsRemovable(targetComponentEditor->GetComponents())
|| !AreComponentsDraggable(targetComponentEditor->GetComponents())
|| (globalRect.center().y() > GetWidgetGlobalRect(targetComponentEditor).center().y())))
{
if (targetItr == m_componentEditors.end() || targetComponentEditor == m_componentEditors.back() || !targetComponentEditor->isVisible())
@@ -211,6 +211,7 @@ namespace AzToolsFramework
// EntityPropertEditorRequestBus
void GetSelectedAndPinnedEntities(EntityIdList& selectedEntityIds) override;
void GetSelectedEntities(EntityIdList& selectedEntityIds) override;
void SetNewComponentId(AZ::ComponentId componentId) override;
bool IsEntitySelected(const AZ::EntityId& id) const;
bool IsSingleEntitySelected(const AZ::EntityId& id) const;
@@ -237,6 +238,9 @@ namespace AzToolsFramework
static bool DoesComponentPassFilter(const AZ::Component* component, const ComponentFilter& filter);
static bool IsComponentRemovable(const AZ::Component* component);
bool AreComponentsRemovable(const AZ::Entity::ComponentArrayType& components) const;
static AZStd::optional<int> GetFixedComponentListIndex(const AZ::Component* component);
static bool IsComponentDraggable(const AZ::Component* component);
bool AreComponentsDraggable(const AZ::Entity::ComponentArrayType& components) const;
bool AreComponentsCopyable(const AZ::Entity::ComponentArrayType& components) const;
void AddMenuOptionsForComponents(QMenu& menu, const QPoint& position);
@@ -568,6 +572,9 @@ namespace AzToolsFramework
void ConnectToEntityBuses(const AZ::EntityId& entityId);
void DisconnectFromEntityBuses(const AZ::EntityId& entityId);
//! Stores a component id to be focused on next time the UI updates.
AZStd::optional<AZ::ComponentId> m_newComponentId;
private slots:
void OnPropertyRefreshRequired(); // refresh is needed for a property.
void UpdateContents();
@@ -68,6 +68,7 @@ namespace AzToolsFramework
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
const AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(entityId);
AzFramework::EntityDebugDisplayEventBus::Event(
entityId, &AzFramework::EntityDebugDisplayEvents::DisplayEntityViewport,
viewportInfo, debugDisplay);
@@ -84,10 +85,9 @@ namespace AzToolsFramework
if (ed_visibility_showAggregateEntityTransformedLocalBounds)
{
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM);
AZ::Transform worldFromLocal = entity->GetTransform()->GetWorldTM();
if (const AZ::Aabb localAabb = AzFramework::CalculateEntityLocalBoundsUnion(entityId); localAabb.IsValid())
if (const AZ::Aabb localAabb = AzFramework::CalculateEntityLocalBoundsUnion(entity); localAabb.IsValid())
{
const AZ::Aabb worldAabb = localAabb.GetTransformedAabb(worldFromLocal);
debugDisplay.SetColor(AZ::Colors::Turquoise);
@@ -97,7 +97,7 @@ namespace AzToolsFramework
if (ed_visibility_showAggregateEntityWorldBounds)
{
if (const AZ::Aabb worldAabb = AzFramework::CalculateEntityWorldBoundsUnion(entityId); worldAabb.IsValid())
if (const AZ::Aabb worldAabb = AzFramework::CalculateEntityWorldBoundsUnion(entity); worldAabb.IsValid())
{
debugDisplay.SetColor(AZ::Colors::Magenta);
debugDisplay.DrawWireBox(worldAabb.GetMin(), worldAabb.GetMax());
@@ -13,7 +13,9 @@
#include "EditorSelectionUtil.h"
#include <AzCore/Math/Aabb.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Math/IntersectSegment.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzFramework/Visibility/BoundsBus.h>
#include <AzToolsFramework/API/ComponentEntitySelectionBus.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
@@ -28,7 +30,8 @@ namespace AzToolsFramework
{
if (Centered(pivot))
{
if (const AZ::Aabb localBound = AzFramework::CalculateEntityLocalBoundsUnion(entityId);
const AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(entityId);
if (const AZ::Aabb localBound = AzFramework::CalculateEntityLocalBoundsUnion(entity);
localBound.IsValid())
{
return localBound.GetCenter();
@@ -17,13 +17,13 @@
#include <AzToolsFramework/Application/ToolsApplication.h>
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
#include <AzToolsFramework/ToolsComponents/ScriptEditorComponent.h>
#include <AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx>
#include <AzToolsFramework/API/EntityPropertyEditorRequestsBus.h>
#include <AzToolsFramework/ToolsComponents/EditorLockComponent.h>
#include <AzToolsFramework/ToolsComponents/EditorVisibilityComponent.h>
#include <AzToolsFramework/ViewportSelection/EditorDefaultSelection.h>
#include <AzCore/IO/Streamer/StreamerComponent.h>
#include <AzCore/Asset/AssetManagerComponent.h>
#include <AzCore/std/sort.h>
@@ -55,7 +55,7 @@ namespace UnitTest
TEST(EntityPropertyEditorTests, PrioritySort_NonTransformAsFirstItem_TransformMovesToTopRemainderUnchanged)
{
ComponentApplication app;
ToolsApplication app;
AZ::Entity::ComponentArrayType unorderedComponents;
AZ::Entity::ComponentArrayType orderedComponents;
@@ -68,12 +68,18 @@ namespace UnitTest
Entity* systemEntity = app.Create(desc, startupParams);
// Need to reflect the components so that edit attribute used for sorting, such as FixedComponentListIndex, get set.
app.RegisterComponentDescriptor(AzToolsFramework::Components::TransformComponent::CreateDescriptor());
app.RegisterComponentDescriptor(AzToolsFramework::Components::ScriptEditorComponent::CreateDescriptor());
app.RegisterComponentDescriptor(AZ::AssetManagerComponent::CreateDescriptor());
// Add more than 31 components, as we are testing the case where the sort fails when there are 32 or more items.
const int numFillerItems = 32;
for (int commentIndex = 0; commentIndex < numFillerItems; commentIndex++)
{
unorderedComponents.insert(unorderedComponents.begin(), systemEntity->CreateComponent(AZ::StreamerComponent::RTTI_Type()));
unorderedComponents.insert(unorderedComponents.begin(), systemEntity->CreateComponent(
AzToolsFramework::Components::ScriptEditorComponent::RTTI_Type()));
}
// Add a TransformComponent at the end which should be sorted to the beginning by the priority sort.
@@ -62,8 +62,8 @@ namespace UnitTest
SetupRowOfEntities(AZ::Vector3::CreateAxisX(-20.0f), AZ::Vector3::CreateAxisX(2.0f));
// request the entity union bounds system to update
AzFramework::EntityBoundsUnionRequestBus::Broadcast(
&AzFramework::EntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests);
AzFramework::IEntityBoundsUnionRequestBus::Broadcast(
&AzFramework::IEntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests);
// create default camera looking down the negative y-axis moved just back from the origin
AzFramework::CameraState cameraState = AzFramework::CreateDefaultCamera(
@@ -101,8 +101,8 @@ namespace UnitTest
SetupRowOfEntities(AZ::Vector3::CreateAxisX(-20.0f), AZ::Vector3::CreateAxisX(2.0f));
// request the entity union bounds system to update
AzFramework::EntityBoundsUnionRequestBus::Broadcast(
&AzFramework::EntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests);
AzFramework::IEntityBoundsUnionRequestBus::Broadcast(
&AzFramework::IEntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests);
// create default camera looking down the negative x-axis moved along the x-axis and tilted slightly down
AzFramework::CameraState cameraState = AzFramework::CreateDefaultCamera(
@@ -143,15 +143,15 @@ namespace UnitTest
SetupRowOfEntities(AZ::Vector3::CreateAxisX(-20.0f), AZ::Vector3::CreateAxisX(2.0f));
// request the entity union bounds system to update
AzFramework::EntityBoundsUnionRequestBus::Broadcast(
&AzFramework::EntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests);
AzFramework::IEntityBoundsUnionRequestBus::Broadcast(
&AzFramework::IEntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests);
const AZ::EntityId entityIdToMove = m_editorEntityIds[10];
AZ::TransformBus::Event(
entityIdToMove, &AZ::TransformBus::Events::SetWorldTranslation, AZ::Vector3::CreateAxisZ(100.0f));
AzFramework::EntityBoundsUnionRequestBus::Broadcast(
&AzFramework::EntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests);
AzFramework::IEntityBoundsUnionRequestBus::Broadcast(
&AzFramework::IEntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests);
// create default camera looking down the negative y-axis moved just back from the origin
AzFramework::CameraState cameraState = AzFramework::CreateDefaultCamera(
@@ -241,8 +241,8 @@ namespace UnitTest
{
m_localAabb = localAabb;
AzFramework::EntityBoundsUnionRequestBus::Broadcast(
&AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId());
AzFramework::IEntityBoundsUnionRequestBus::Broadcast(
&AzFramework::IEntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId());
}
TEST_F(EditorVisibilityFixture, UpdatedBoundsIntersectingFrustumAddsVisibleEntity)
@@ -264,8 +264,8 @@ namespace UnitTest
entityId, &AZ::TransformBus::Events::SetWorldTranslation, AZ::Vector3(40.0f, -3.0f, 20.0f));
// request the entity union bounds system to update
AzFramework::EntityBoundsUnionRequestBus::Broadcast(
&AzFramework::EntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests);
AzFramework::IEntityBoundsUnionRequestBus::Broadcast(
&AzFramework::IEntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests);
// create default camera looking down the positive x-axis moved to position offset from world origin
AzFramework::CameraState cameraState = AzFramework::CreateDefaultCamera(
@@ -288,8 +288,8 @@ namespace UnitTest
testBoundComponent->ChangeBounds(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-2.5f), AZ::Vector3(2.5f)));
// perform an 'update' of the visibility system
AzFramework::EntityBoundsUnionRequestBus::Broadcast(
&AzFramework::EntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests);
AzFramework::IEntityBoundsUnionRequestBus::Broadcast(
&AzFramework::IEntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests);
entityVisibilityQuery.UpdateVisibility(cameraState);
@@ -1100,6 +1100,10 @@ namespace UnitTest
void UnregisterComponentDescriptor(const ComponentDescriptor*) override {}
void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler&) override {}
void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler&) override {}
void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override {}
void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override {}
void SignalEntityActivated(Entity*) override {}
void SignalEntityDeactivated(Entity*) override {}
bool AddEntity(Entity*) override { return true; }
bool RemoveEntity(Entity*) override { return true; }
bool DeleteEntity(const EntityId&) override { return true; }
@@ -1125,6 +1129,7 @@ namespace UnitTest
AllocatorsFixture::SetUp();
ComponentApplicationBus::Handler::BusConnect();
AZ::Interface<AZ::ComponentApplicationRequests>::Register(this);
m_serializeContext.reset(aznew AZ::SerializeContext(true, true));
Entity::Reflect(m_serializeContext.get());
@@ -1139,6 +1144,7 @@ namespace UnitTest
m_descriptors.set_capacity(0);
m_serializeContext.reset();
AZ::Interface<AZ::ComponentApplicationRequests>::Unregister(this);
ComponentApplicationBus::Handler::BusDisconnect();
AllocatorsFixture::TearDown();
+4
View File
@@ -279,6 +279,10 @@ namespace UnitTest
MOCK_METHOD1(UnregisterComponentDescriptor, void (const AZ::ComponentDescriptor*));
MOCK_METHOD1(RegisterEntityAddedEventHandler, void(AZ::EntityAddedEvent::Handler&));
MOCK_METHOD1(RegisterEntityRemovedEventHandler, void(AZ::EntityRemovedEvent::Handler&));
MOCK_METHOD1(RegisterEntityActivatedEventHandler, void(AZ::EntityActivatedEvent::Handler&));
MOCK_METHOD1(RegisterEntityDeactivatedEventHandler, void(AZ::EntityDeactivatedEvent::Handler&));
MOCK_METHOD1(SignalEntityActivated, void(AZ::Entity*));
MOCK_METHOD1(SignalEntityDeactivated, void(AZ::Entity*));
MOCK_METHOD1(RemoveEntity, bool (AZ::Entity*));
MOCK_METHOD1(DeleteEntity, bool (const AZ::EntityId&));
MOCK_METHOD1(GetEntityName, AZStd::string (const AZ::EntityId&));