LYN-8629 | Read-Only Entities - Setup (#6059)

* Introduce read-only entity interface, handler and unit tests.

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

* Switch from a push paradigm to a pull paradigm - handlers get to implement logic to determine if an entity should be read-only. This allows multiple systems to weigh into whether an entity is read-only.

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

* Fixed to missing call in test

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

* Renaming ReadOnlyEntityQueryNotificationBus to ReadOnlyEntityQueryRequestBus for consistency with engine patterns.

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>
This commit is contained in:
Danilo Aimini
2021-12-01 12:24:49 -08:00
committed by GitHub
parent 68bf7c85ed
commit e16781e6b6
11 changed files with 574 additions and 0 deletions
@@ -30,6 +30,7 @@
#include <AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h>
#include <AzToolsFramework/Entity/EditorEntityContextComponent.h>
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
#include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntitySystemComponent.h>
#include <AzToolsFramework/FocusMode/FocusModeSystemComponent.h>
#include <AzToolsFramework/Slice/SliceMetadataEntityContextComponent.h>
#include <AzToolsFramework/Prefab/PrefabSystemComponent.h>
@@ -268,6 +269,7 @@ namespace AzToolsFramework
azrtti_typeid<Components::EditorEntityUiSystemComponent>(),
azrtti_typeid<FocusModeSystemComponent>(),
azrtti_typeid<ContainerEntitySystemComponent>(),
azrtti_typeid<ReadOnlyEntitySystemComponent>(),
azrtti_typeid<SliceMetadataEntityContextComponent>(),
azrtti_typeid<Prefab::PrefabSystemComponent>(),
azrtti_typeid<EditorEntityFixupComponent>(),
@@ -23,6 +23,7 @@
#include <AzToolsFramework/Entity/EditorEntityModelComponent.h>
#include <AzToolsFramework/Entity/EditorEntitySearchComponent.h>
#include <AzToolsFramework/Entity/EditorEntitySortComponent.h>
#include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntitySystemComponent.h>
#include <AzToolsFramework/FocusMode/FocusModeSystemComponent.h>
#include <AzToolsFramework/PropertyTreeEditor/PropertyTreeEditorComponent.h>
#include <AzToolsFramework/Render/EditorIntersectorComponent.h>
@@ -75,6 +76,7 @@ namespace AzToolsFramework
EditorEntityFixupComponent::CreateDescriptor(),
EntityUtilityComponent::CreateDescriptor(),
ContainerEntitySystemComponent::CreateDescriptor(),
ReadOnlyEntitySystemComponent::CreateDescriptor(),
FocusModeSystemComponent::CreateDescriptor(),
SliceMetadataEntityContextComponent::CreateDescriptor(),
SliceRequestComponent::CreateDescriptor(),
@@ -0,0 +1,63 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Component/EntityId.h>
#include <AzCore/EBus/EBus.h>
#include <AzFramework/Entity/EntityContext.h>
namespace AzToolsFramework
{
//! Used to notify changes of state for read-only entities.
class ReadOnlyEntityPublicNotifications
: public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = AzFramework::EntityContextId;
//////////////////////////////////////////////////////////////////////////
//! Triggered when an entity's read-only status changes.
//! @param entityId The entity whose status has changed.
//! @param readOnly The read-only state the container was changed to.
virtual void OnReadOnlyEntityStatusChanged([[maybe_unused]] const AZ::EntityId& entityId, [[maybe_unused]] bool readOnly) {}
protected:
~ReadOnlyEntityPublicNotifications() = default;
};
using ReadOnlyEntityPublicNotificationBus = AZ::EBus<ReadOnlyEntityPublicNotifications>;
//! Used by the ReadOnlyEntitySystemComponent to query the read-only state of entities as set by systems using the API.
class ReadOnlyEntityQueryRequests
: public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = AzFramework::EntityContextId;
//////////////////////////////////////////////////////////////////////////
//! Triggered when an entity's read-only status is queried.
//! Allows multiple systems to weigh in on the read-only status of an entity.
//! @param entityId The entity whose status has changed.
//! @param[out] isReadOnly The output of the query. Should only be changed to true, and left untouched if false.
virtual void IsReadOnly(const AZ::EntityId& entityId, bool& isReadOnly) = 0;
protected:
~ReadOnlyEntityQueryRequests() = default;
};
using ReadOnlyEntityQueryRequestBus = AZ::EBus<ReadOnlyEntityQueryRequests>;
} // namespace AzToolsFramework
@@ -0,0 +1,43 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Interface/Interface.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Entity/EntityContextBus.h>
namespace AzToolsFramework
{
//! An entity registered as read-only cannot be altered in the editor.
class ReadOnlyEntityPublicInterface
{
public:
AZ_RTTI(ReadOnlyEntityPublicInterface, "{921FE15B-6EBD-47F0-8238-BC63318DEDEA}");
//! Returns whether the entity id provided is registered as read-only.
virtual bool IsReadOnly(const AZ::EntityId& entityId) = 0;
};
//! An entity registered as read-only cannot be altered in the editor.
class ReadOnlyEntityQueryInterface
{
public:
AZ_RTTI(ReadOnlyEntityQueryInterface, "{2ACD63C5-1F3E-4DE8-880E-8115F857D329}");
//! Refreshes the cached read-only status for the entities provided.
//! @param entityIds The entityIds whose read-only state will be queried again.
virtual void RefreshReadOnlyState(const EntityIdList& entityIds) = 0;
//! Refreshes the cached read-only status for all entities.
//! Useful when disconnecting a handler at runtime.
virtual void RefreshReadOnlyStateForAllEntities() = 0;
};
} // namespace AzToolsFramework
@@ -0,0 +1,99 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntitySystemComponent.h>
#include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntityBus.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
namespace AzToolsFramework
{
void ReadOnlyEntitySystemComponent::Activate()
{
AZ::Interface<ReadOnlyEntityQueryInterface>::Register(this);
AZ::Interface<ReadOnlyEntityPublicInterface>::Register(this);
EditorEntityContextNotificationBus::Handler::BusConnect();
}
void ReadOnlyEntitySystemComponent::Deactivate()
{
EditorEntityContextNotificationBus::Handler::BusDisconnect();
AZ::Interface<ReadOnlyEntityPublicInterface>::Unregister(this);
AZ::Interface<ReadOnlyEntityQueryInterface>::Unregister(this);
}
void ReadOnlyEntitySystemComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<ReadOnlyEntitySystemComponent, AZ::Component>()->Version(1);
}
}
void ReadOnlyEntitySystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC_CE("ReadOnlyEntityService"));
}
bool ReadOnlyEntitySystemComponent::IsReadOnly(const AZ::EntityId& entityId)
{
if (!m_readOnlystates.contains(entityId))
{
QueryReadOnlyStateForEntity(entityId);
}
return m_readOnlystates[entityId];
}
void ReadOnlyEntitySystemComponent::RefreshReadOnlyState(const EntityIdList& entityIds)
{
for (const AZ::EntityId entityId : entityIds)
{
bool wasReadOnly = m_readOnlystates[entityId];
QueryReadOnlyStateForEntity(entityId);
if (bool isReadOnly = m_readOnlystates[entityId]; wasReadOnly != isReadOnly)
{
ReadOnlyEntityPublicNotificationBus::Broadcast(
&ReadOnlyEntityPublicNotificationBus::Events::OnReadOnlyEntityStatusChanged, entityId, isReadOnly);
}
}
}
void ReadOnlyEntitySystemComponent::RefreshReadOnlyStateForAllEntities()
{
for (auto elem : m_readOnlystates)
{
AZ::EntityId entityId = elem.first;
bool wasReadOnly = m_readOnlystates[entityId];
QueryReadOnlyStateForEntity(entityId);
if (bool isReadOnly = m_readOnlystates[entityId]; wasReadOnly != isReadOnly)
{
ReadOnlyEntityPublicNotificationBus::Broadcast(
&ReadOnlyEntityPublicNotificationBus::Events::OnReadOnlyEntityStatusChanged, entityId, isReadOnly);
}
}
}
void ReadOnlyEntitySystemComponent::OnContextReset()
{
m_readOnlystates.clear();
}
void ReadOnlyEntitySystemComponent::QueryReadOnlyStateForEntity(const AZ::EntityId& entityId)
{
bool isReadOnly = false;
ReadOnlyEntityQueryRequestBus::Broadcast(
&ReadOnlyEntityQueryRequestBus::Events::IsReadOnly, entityId, isReadOnly);
m_readOnlystates[entityId] = isReadOnly;
}
} // namespace AzToolsFramework
@@ -0,0 +1,56 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Component/Component.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
#include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntityInterface.h>
namespace AzToolsFramework
{
//! System Component to track read-only entity registration.
//! An entity registered as ReadOnly cannot be altered in the Editor.
class ReadOnlyEntitySystemComponent final
: public AZ::Component
, private ReadOnlyEntityPublicInterface
, private ReadOnlyEntityQueryInterface
, private EditorEntityContextNotificationBus::Handler
{
public:
AZ_COMPONENT(ReadOnlyEntitySystemComponent, "{B32EB03F-D88F-4B3A-9C16-071AF04DA646}");
ReadOnlyEntitySystemComponent() = default;
virtual ~ReadOnlyEntitySystemComponent() = default;
// AZ::Component overrides ...
void Activate() override;
void Deactivate() override;
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
// ReadOnlyEntityPublicNotifications overrides ...
bool IsReadOnly(const AZ::EntityId& entityId) override;
// ReadOnlyEntityQueryInterface overrides ...
void RefreshReadOnlyState(const EntityIdList& entityIds) override;
void RefreshReadOnlyStateForAllEntities() override;
// EditorEntityContextNotificationBus overrides ...
void OnContextReset() override;
private:
void QueryReadOnlyStateForEntity(const AZ::EntityId& entityId);
AZStd::unordered_map<AZ::EntityId, bool> m_readOnlystates;
};
} // namespace AzToolsFramework
@@ -159,6 +159,10 @@ set(FILES
Entity/SliceEditorEntityOwnershipServiceBus.h
Entity/EntityUtilityComponent.h
Entity/EntityUtilityComponent.cpp
Entity/ReadOnly/ReadOnlyEntityInterface.h
Entity/ReadOnly/ReadOnlyEntityBus.h
Entity/ReadOnly/ReadOnlyEntitySystemComponent.cpp
Entity/ReadOnly/ReadOnlyEntitySystemComponent.h
Fingerprinting/TypeFingerprinter.h
Fingerprinting/TypeFingerprinter.cpp
FocusMode/FocusModeInterface.h