Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,95 @@
/*
* 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 <AzToolsFramework/ToolsComponents/AzToolsFrameworkConfigurationSystemComponent.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzFramework/Scene/Scene.h>
#include <AzFramework/Scene/SceneSystemBus.h>
#include <AzToolsFramework/Editor/EditorSettingsAPIBus.h>
#include <AzToolsFramework/Entity/EditorEntityContextComponent.h>
namespace AzToolsFramework
{
void AzToolsFrameworkConfigurationSystemComponent::Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<AzToolsFrameworkConfigurationSystemComponent, AZ::Component>();
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<AzToolsFrameworkConfigurationSystemComponent>(
"AzToolsFramework Configuration Component", "System component responsible for configuring AzToolsFramework")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "Editor")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
;
}
}
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->EBus<EditorSettingsAPIBus>("EditorSettingsAPIBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
->Attribute(AZ::Script::Attributes::Category, "Editor")
->Attribute(AZ::Script::Attributes::Module, "editor")
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Event("BuildSettingsList", &EditorSettingsAPIRequests::BuildSettingsList)
->Event("GetValue", &EditorSettingsAPIRequests::GetValue)
->Event("SetValue", &EditorSettingsAPIRequests::SetValue)
;
}
}
void AzToolsFrameworkConfigurationSystemComponent::Activate()
{
// Associate the EditorEntityContext with the default scene.
AzFramework::EntityContextId editorEntityContextId;
EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
AzFramework::Scene* defaultScene = nullptr;
AzFramework::SceneSystemRequestBus::BroadcastResult(defaultScene, &AzFramework::SceneSystemRequests::GetScene, "default");
if (!editorEntityContextId.IsNull() && defaultScene)
{
bool success = false;
AzFramework::SceneSystemRequestBus::BroadcastResult(success, &AzFramework::SceneSystemRequests::SetSceneForEntityContextId, editorEntityContextId, defaultScene);
}
}
void AzToolsFrameworkConfigurationSystemComponent::Deactivate()
{
}
void AzToolsFrameworkConfigurationSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("AzToolsFrameworkConfigurationSystemComponentService", 0xfc4f9667));
}
void AzToolsFrameworkConfigurationSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("AzToolsFrameworkConfigurationSystemComponentService", 0xfc4f9667));
}
void AzToolsFrameworkConfigurationSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
dependent.push_back(AZ_CRC("AzFrameworkConfigurationSystemComponentService", 0xcc49c96e));
dependent.push_back(AZ_CRC("SceneSystemComponentService", 0xd8975435));
dependent.push_back(AZ_CRC("EditorEntityContextService", 0x28d93a43));
}
} // AzToolsFramework
@@ -0,0 +1,40 @@
/*
* 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 <AzCore/Component/Component.h>
namespace AzToolsFramework
{
class AzToolsFrameworkConfigurationSystemComponent
: public AZ::Component
{
public:
AZ_COMPONENT(AzToolsFrameworkConfigurationSystemComponent, "{088BE6DC-C01C-415F-AE6D-83C6C0CDB108}", AZ::Component);
AzToolsFrameworkConfigurationSystemComponent() = default;
~AzToolsFrameworkConfigurationSystemComponent() override = default;
//////////////////////////////////////////////////////////////////////////
// Component overrides
void Activate() override;
void Deactivate() override;
//////////////////////////////////////////////////////////////////////////
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
};
} // AzToolsFramework
@@ -0,0 +1,89 @@
/*
* 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 "AzToolsFramework_precompiled.h"
#include "ComponentAssetMimeDataContainer.h"
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/IO/GenericStreams.h>
#include <AzCore/IO/ByteContainerStream.h>
#include <AzCore/Serialization/Utils.h>
#include <AzCore/Serialization/ObjectStream.h>
#include <QtCore/QMimeData>
namespace AzToolsFramework
{
void ComponentAssetMimeData::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<ComponentAssetMimeData>()
->Field("m_assetId", &ComponentAssetMimeData::m_assetId)
->Field("m_classId", &ComponentAssetMimeData::m_classId)
->Version(1);
}
}
void ComponentAssetMimeDataContainer::Reflect(AZ::ReflectContext* context)
{
AzToolsFramework::ComponentAssetMimeData::Reflect(context);
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<ComponentAssetMimeDataContainer>()
->Field("m_assets", &ComponentAssetMimeDataContainer::m_assets)
->Version(1);
}
}
void ComponentAssetMimeDataContainer::AddComponentAsset(const AZ::Uuid& classId, const AZ::Data::AssetId& assetId)
{
ComponentAssetMimeData newAsset(classId, assetId);
m_assets.push_back(newAsset);
}
void ComponentAssetMimeDataContainer::AddToMimeData(QMimeData* mimeData) const
{
if (mimeData != nullptr)
{
// There are a few conversion steps.
AZStd::vector<char> buffer;
AZ::IO::ByteContainerStream<AZStd::vector<char> > byteStream(&buffer);
AZ::Utils::SaveObjectToStream(byteStream, AZ::DataStream::ST_BINARY, this);
QByteArray dataArray(buffer.data(), static_cast<int>(sizeof(char) * buffer.size()));
mimeData->setData(GetMimeType(), dataArray);
}
}
bool ComponentAssetMimeDataContainer::FromMimeData(const QMimeData* mimeData)
{
if (mimeData != nullptr && mimeData->hasFormat(GetMimeType()))
{
QByteArray arrayData = mimeData->data(GetMimeType());
AZ::IO::MemoryStream ms(arrayData.constData(), arrayData.size());
ComponentAssetMimeDataContainer* pContainer = AZ::Utils::LoadObjectFromStream<ComponentAssetMimeDataContainer>(ms, nullptr);
if (pContainer)
{
m_assets = AZStd::move(pContainer->m_assets);
delete pContainer;
return true;
}
}
return false;
}
}
@@ -0,0 +1,81 @@
/*
* 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.
*
*/
#ifndef COMPONENT_ASSET_MIME_DATA_CONTAINER_H
#define COMPONENT_ASSET_MIME_DATA_CONTAINER_H
#include <AzCore/base.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AZ
{
struct ClassDataReflection;
}
class QMimeData;
namespace AzToolsFramework
{
class ComponentAssetMimeData
{
public:
virtual ~ComponentAssetMimeData() { }
AZ_RTTI(ComponentAssetMimeData, "{39C0AF31-9CC2-4E98-0E27-8025D15F4DF5}");
AZ_CLASS_ALLOCATOR(ComponentAssetMimeData, AZ::SystemAllocator, 0);
ComponentAssetMimeData()
{
m_classId = AZ::Uuid::CreateNull();
}
ComponentAssetMimeData(AZ::Uuid classId, AZ::Data::AssetId assetId)
: m_assetId(assetId)
, m_classId(classId)
{
}
AZ::Data::AssetId m_assetId;
AZ::Uuid m_classId;
static void Reflect(AZ::ReflectContext* context);
};
/// A mime container used for an asset and a component type to assign that asset into.
/// Used for creating new components directly from assets.
class ComponentAssetMimeDataContainer
{
public:
virtual ~ComponentAssetMimeDataContainer() { }
AZ_RTTI(ComponentAssetMimeDataContainer, "{7744B99F-2FE9-49AF-DEB2-1562BDA04238}");
AZ_CLASS_ALLOCATOR(ComponentAssetMimeDataContainer, AZ::SystemAllocator, 0);
AZStd::vector< ComponentAssetMimeData > m_assets;
/// Create a new ComponentAssetMimeData and add it to the internal vector.
void AddComponentAsset(const AZ::Uuid& classId, const AZ::Data::AssetId& assetId);
/// Add mime data of this type to the specified QMimeData.
void AddToMimeData(QMimeData* mimeData) const;
/// Retrieve mime data of this type from the specified QMimeData. Return true if successful.
bool FromMimeData(const QMimeData* mimeData);
static void Reflect(AZ::ReflectContext* context);
static QString GetMimeType() { return "editor/componentasset"; }
};
}
#endif // EDITOR_ASSET_ID_CONTAINER_H
@@ -0,0 +1,192 @@
/*
* 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 "ComponentMimeData.h"
#include <QMimeData>
#include <QDataStream>
#include <QClipboard>
#include <QApplication>
#include <AzCore/Serialization/Utils.h>
#include <AzCore/IO/ByteContainerStream.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
namespace AzToolsFramework
{
QString ComponentTypeMimeData::GetMimeType()
{
return "application/x-amazon-lumberyard-editorcomponenttypes";
}
AZStd::unique_ptr<QMimeData> ComponentTypeMimeData::Create(const ClassDataContainer& container)
{
QByteArray dataArray;
AZStd::unique_ptr<QMimeData> mimeData = std::make_unique<QMimeData>();
QDataStream stream(&dataArray, QIODevice::WriteOnly);
// Count how many valid items we have so we don't stream out nullptrs
quint64 numItems = 0;
for (auto item : container)
{
AZ_Assert(item, "null class type provided as input to ComponentMimeData::Create");
if (item)
{
++numItems;
}
}
stream << numItems;
for (auto item : container)
{
if (!item)
{
continue;
}
quint64 classDataPtr = reinterpret_cast<quint64>(item);
stream << classDataPtr;
}
mimeData->setData(GetMimeType(), dataArray);
return mimeData;
}
bool ComponentTypeMimeData::Get(const QMimeData* mimeData, ClassDataContainer& container)
{
if (mimeData && mimeData->hasFormat(GetMimeType()))
{
container.clear();
QByteArray arrayData = mimeData->data(GetMimeType());
QDataStream stream(&arrayData, QIODevice::ReadOnly);
quint64 numItems = 0;
stream >> numItems;
for (size_t i = 0; i < numItems; ++i)
{
quint64 ptrAddr;
stream >> ptrAddr;
auto classData = reinterpret_cast<ClassDataType>(ptrAddr);
container.push_back(classData);
}
return !container.empty();
}
return false;
}
void ComponentMimeData::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<ComponentMimeData>()
->Field("Components", &ComponentMimeData::m_components);
}
}
QString ComponentMimeData::GetMimeType()
{
return "application/x-amazon-lumberyard-editorcomponentdata";
}
AZStd::unique_ptr<QMimeData> ComponentMimeData::Create(const ComponentDataContainer& components)
{
AZ::SerializeContext* context;
EBUS_EVENT_RESULT(context, AZ::ComponentApplicationBus, GetSerializeContext);
if (!context)
{
AZ_Assert(context, "No serialize context");
return nullptr;
}
// Extract the type data, put it in the mime data for early checking later
ComponentTypeMimeData::ClassDataContainer componentClassTypes;
for (AZ::Component* component : components)
{
AZ_Assert(component, "null component provided as input to ComponentMimeData::Create");
if (!component)
{
continue;
}
// Get the underlying component type if wrapped with a generic component wrapper
auto classData = context->FindClassData(GetComponentTypeId(component));
if (classData)
{
componentClassTypes.push_back(classData);
}
}
// Pack the components into a helper class for serialization
ComponentMimeData componentMimeData;
componentMimeData.m_components = components;
// Save the helper class into a buffer to pack into mime data
AZStd::vector<char> buffer;
AZ::IO::ByteContainerStream<AZStd::vector<char>> byteStream(&buffer);
if (!AZ::Utils::SaveObjectToStream(byteStream, AZ::DataStream::ST_XML, &componentMimeData))
{
return nullptr;
}
QByteArray dataArray(buffer.data(), static_cast<int>(sizeof(char) * buffer.size()));
AZStd::unique_ptr<QMimeData> mimeData = ComponentTypeMimeData::Create(componentClassTypes);
if (mimeData)
{
mimeData->setData(GetMimeType(), dataArray);
}
return mimeData;
}
void ComponentMimeData::GetComponentDataFromMimeData(const QMimeData* mimeData, ComponentDataContainer& componentData)
{
if (!mimeData || !mimeData->hasFormat(GetMimeType()))
{
return;
}
QByteArray arrayData = mimeData->data(GetMimeType());
AZ::IO::MemoryStream memoryStream(arrayData.constData(), arrayData.size());
ComponentMimeData* componentMimeData = AZ::Utils::LoadObjectFromStream<ComponentMimeData>(memoryStream);
if (!componentMimeData)
{
return;
}
componentData.clear();
componentData = AZStd::move(componentMimeData->m_components);
delete componentMimeData;
}
const QMimeData* ComponentMimeData::GetComponentMimeDataFromClipboard()
{
// Do we have stuff on the clipboard?
QClipboard* clipboard = QApplication::clipboard();
const QMimeData* mimeData = clipboard->mimeData();
if (mimeData && mimeData->hasFormat(GetMimeType()))
{
return mimeData;
}
return nullptr;
}
void ComponentMimeData::PutComponentMimeDataOnClipboard(AZStd::unique_ptr<QMimeData> mimeData)
{
QClipboard* clipboard = QApplication::clipboard();
clipboard->setMimeData(mimeData.release());
}
}
@@ -0,0 +1,72 @@
/*
* 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 <AzCore/PlatformDef.h>
#include <QString>
AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") // 4251: 'QTreeWidgetItemIterator::d_ptr': class 'QScopedPointer<QTreeWidgetItemIteratorPrivate,QScopedPointerDeleter<T>>' needs to have dll-interface to be used by clients of class 'QTreeWidgetItemIterator'
#include <QTreeWidgetItem>
AZ_POP_DISABLE_WARNING
#include <AzCore/base.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/Serialization/SerializeContext.h>
class QMimeData;
namespace AZ
{
class Component;
}
namespace AzToolsFramework
{
class ComponentTypeMimeData
{
public:
using ClassDataType = const AZ::SerializeContext::ClassData*;
using ClassDataContainer = AZStd::vector<ClassDataType>;
static QString GetMimeType();
static AZStd::unique_ptr<QMimeData> Create(const ClassDataContainer& container);
static bool Get(const QMimeData* mimeData, ClassDataContainer& container);
};
class ComponentMimeData
{
public:
virtual ~ComponentMimeData() = default;
AZ_RTTI(ComponentMimeData, "{55A643D6-DDE9-4D48-9B6B-B14C46B6C08B}");
AZ_CLASS_ALLOCATOR(ComponentMimeData, AZ::SystemAllocator, 0);
using ComponentDataContainer = AZStd::vector<AZ::Component*>;
static void Reflect(AZ::ReflectContext* context);
static QString GetMimeType();
static AZStd::unique_ptr<QMimeData> Create(const ComponentDataContainer& components);
static void GetComponentDataFromMimeData(const QMimeData* mimeData, ComponentDataContainer& componentData);
static const QMimeData* GetComponentMimeDataFromClipboard();
static void PutComponentMimeDataOnClipboard(AZStd::unique_ptr<QMimeData> mimeData);
private:
ComponentDataContainer m_components;
};
}
@@ -0,0 +1,114 @@
/*
* 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 "AzToolsFramework_precompiled.h"
#include "EditorAssetMimeDataContainer.h"
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/IO/GenericStreams.h>
#include <AzCore/IO/ByteContainerStream.h>
#include <AzCore/Serialization/Utils.h>
#include <AzCore/Serialization/ObjectStream.h>
#include <QtCore/QMimeData>
namespace AzToolsFramework
{
void EditorAssetMimeData::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<EditorAssetMimeData>()
->Field("m_assetId", &EditorAssetMimeData::m_assetId)
->Field("m_assetType", &EditorAssetMimeData::m_assetType)
->Version(1);
}
}
void EditorAssetMimeDataContainer::Reflect(AZ::ReflectContext* context)
{
AzToolsFramework::EditorAssetMimeData::Reflect(context);
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<EditorAssetMimeDataContainer>()
->Field("m_assets", &EditorAssetMimeDataContainer::m_assets)
->Version(2);
}
}
bool EditorAssetMimeDataContainer::ToBuffer(AZStd::vector<char>& buffer)
{
buffer.clear();
AZ::IO::ByteContainerStream<AZStd::vector<char> > ms(&buffer);
return AZ::Utils::SaveObjectToStream(ms, AZ::DataStream::ST_BINARY, this);
}
bool EditorAssetMimeDataContainer::FromBuffer(const char* data, AZStd::size_t size)
{
AZ::IO::MemoryStream ms(data, size);
EditorAssetMimeDataContainer* pContainer = AZ::Utils::LoadObjectFromStream<EditorAssetMimeDataContainer>(ms, nullptr);
if (pContainer)
{
m_assets = AZStd::move(pContainer->m_assets);
delete pContainer;
return true;
}
return false;
}
bool EditorAssetMimeDataContainer::FromBuffer(const AZStd::vector<char>& buffer)
{
return FromBuffer(buffer.data(), buffer.size());
}
void EditorAssetMimeDataContainer::AddEditorAsset(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType)
{
EditorAssetMimeData newAsset(assetId, assetType);
m_assets.push_back(newAsset);
}
void EditorAssetMimeDataContainer::AddToMimeData(QMimeData* mimeData) const
{
if (mimeData != nullptr)
{
AZStd::vector<char> buffer;
AZ::IO::ByteContainerStream<AZStd::vector<char> > byteStream(&buffer);
AZ::Utils::SaveObjectToStream(byteStream, AZ::DataStream::ST_BINARY, this);
QByteArray dataArray(buffer.data(), static_cast<int>(sizeof(char) * buffer.size()));
mimeData->setData(GetMimeType(), dataArray);
}
}
bool EditorAssetMimeDataContainer::FromMimeData(const QMimeData* mimeData)
{
if (mimeData != nullptr && mimeData->hasFormat(GetMimeType()))
{
QByteArray arrayData = mimeData->data(GetMimeType());
AZ::IO::MemoryStream ms(arrayData.constData(), arrayData.size());
EditorAssetMimeDataContainer* pContainer = AZ::Utils::LoadObjectFromStream<EditorAssetMimeDataContainer>(ms, nullptr);
if (pContainer)
{
m_assets = AZStd::move(pContainer->m_assets);
delete pContainer;
return true;
}
}
return false;
}
}
@@ -0,0 +1,85 @@
/*
* 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.
*
*/
#ifndef EDITOR_ASSET_ID_CONTAINER_H
#define EDITOR_ASSET_ID_CONTAINER_H
#include <AzCore/base.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AZ
{
struct ClassDataReflection;
}
class QMimeData;
namespace AzToolsFramework
{
class EditorAssetMimeData
{
public:
virtual ~EditorAssetMimeData() { }
AZ_RTTI(EditorAssetMimeData, "{844742CD-7D34-4ED0-B798-396A6C0530BF}");
AZ_CLASS_ALLOCATOR(EditorAssetMimeData, AZ::SystemAllocator, 0);
EditorAssetMimeData()
{
}
EditorAssetMimeData(AZ::Data::AssetId assetId, AZ::Data::AssetType assetType)
: m_assetId(assetId)
, m_assetType(assetType)
{
}
AZ::Data::AssetId m_assetId;
AZ::Data::AssetType m_assetType;
static void Reflect(AZ::ReflectContext* context);
};
/// Mime data for copying assets into property fields via drag/drop.
/// The type is used for validation before accepting drops.
class EditorAssetMimeDataContainer
{
public:
virtual ~EditorAssetMimeDataContainer() { }
AZ_RTTI(EditorAssetMimeDataContainer, "{BC72D334-EFF9-40F0-B615-48186E01BDD6}");
AZ_CLASS_ALLOCATOR(EditorAssetMimeDataContainer, AZ::SystemAllocator, 0);
AZStd::vector< EditorAssetMimeData > m_assets;
/// Create a new EditorAssetMimeData and add it to the internal vector.
void AddEditorAsset(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType);
/// Add mime data of this type to the specified QMimeData.
void AddToMimeData(QMimeData* mimeData) const;
/// Retrieve mime data of this type from the specified QMimeData. Return true if successful.
bool FromMimeData(const QMimeData* mimeData);
// utility functions to serialize/deserialize.
bool ToBuffer(AZStd::vector<char>& buffer);
bool FromBuffer(const AZStd::vector<char>& buffer);
bool FromBuffer(const char* data, AZStd::size_t size);
static void Reflect(AZ::ReflectContext* context);
static QString GetMimeType() { return "editor/assetinformation"; }
};
}
#endif // EDITOR_ASSET_ID_CONTAINER_H
@@ -0,0 +1,31 @@
/*
* 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 "AzToolsFramework_precompiled.h"
#include "EditorAssetReference.h"
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Component/Component.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
namespace AzToolsFramework
{
void AssetReferenceBase::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssetReferenceBase>()
->Version(1)
->Field("CurrentAssetID", &AssetReferenceBase::m_currentID);
}
}
}
@@ -0,0 +1,46 @@
/*
* 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.
*
*/
#ifndef EDITOR_ASSET_REFERENCE_H
#define EDITOR_ASSET_REFERENCE_H
#include <AzCore/base.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/RTTI/RTTI.h>
namespace AZ
{
struct ClassDataReflection;
}
namespace AzToolsFramework
{
// the base class of an editor asset reference - this is what you would derive a model reference from, for example
// these guys show up in the editor as a live drag-and-droppable field.
class AssetReferenceBase
{
public:
AZ_RTTI(AssetReferenceBase, "{C30974B6-5831-443D-BFB2-CDF12600164D}");
AssetReferenceBase() {}
virtual ~AssetReferenceBase() {}
virtual AZ::Data::AssetType GetAssetType() const = 0;
const AZ::Data::AssetId& GetCurrentID() const { return m_currentID; }
void SetCurrentID(const AZ::Data::AssetId& value) { m_currentID = value; }
static void Reflect(AZ::ReflectContext* context);
protected:
AZ::Data::AssetId m_currentID;
};
}
#endif
@@ -0,0 +1,107 @@
/*
* 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 <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
#include <AzToolsFramework/ToolsComponents/EditorVisibilityBus.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/EditContextConstants.inl>
namespace AzToolsFramework
{
namespace Components
{
/** EditorComponentAdapter is a utility base class that provides a consistent pattern for implementing components
that operate in the editor but may need to share code in different contexts like the launcher.
EditorComponentAdapter achieves this by delegating to a controller class that implements common behavior instead of
duplicating code between multiple components.
To use the EditorComponentAdapter, 3 classes are required:
- a class that implements the functions required for TController (see below)
- a configuration struct/class which extends AZ::ComponentConfig
- A runtime component that will be generated by the editor comoinent on export
The concrete component extends the adapter and implements behavior which is unique to the component.
TController can handle any common functionality between the runtime and editor component and is where most of the code for the
component will live
TConfiguration is where any data that needs to be serialized out should live.
TController must implement certain functions to conform to the template. These functions mirror those in
AZ::Component and must be accesible to any adapter that follows this pattern:
@code
static void Reflect(AZ::ReflectContext* context);
void Activate(EntityId entityId);
void Deactivate();
void SetConfiguration(const ComponentConfigurationType& config);
const ComponentConfigurationType& GetConfiguration() const;
@endcode
In addition, certain functions will optionally be called if they are available:
@code
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services);
void Init();
@endcode
It is recommended that TController handle the SerializeContext, but the editor components handle
the EditContext. TController can friend itself to the editor component to make this work if required.
*/
template<typename TController, typename TRuntimeComponent, typename TConfiguration = AZ::ComponentConfig>
class EditorComponentAdapter
: public EditorComponentBase
{
public:
AZ_RTTI((EditorComponentAdapter, "{2F5A3669-FFE9-4CD7-B9E2-7FC8100CF1A2}", TController, TRuntimeComponent, TConfiguration), EditorComponentBase);
EditorComponentAdapter() = default;
EditorComponentAdapter(const TConfiguration& configuration);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& services);
// EditorComponentBase overrides ...
void Init() override;
void Activate() override;
void Deactivate() override;
void BuildGameEntity(AZ::Entity* gameEntity) override;
protected:
static void Reflect(AZ::ReflectContext* context);
// AZ::Component overrides ...
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
// general configuration change handler invoked with any property edit
virtual AZ::u32 OnConfigurationChanged();
// determine if the controller should be activated with the editor component or configuration changes
virtual bool ShouldActivateController() const;
TController m_controller;
};
} // namespace Components
} // namespace AzToolsFramework
#include "EditorComponentAdapter.inl"
@@ -0,0 +1,154 @@
/*
* 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 <AzFramework/Components/ComponentAdapterHelpers.h>
namespace AzToolsFramework
{
namespace Components
{
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::EditorComponentAdapter(const TConfiguration& configuration)
: m_controller(configuration)
{
}
//////////////////////////////////////////////////////////////////////////
// Serialization and version conversion
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorComponentAdapter, EditorComponentBase>()
->Version(1)
->Field("Controller", &EditorComponentAdapter::m_controller)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<EditorComponentAdapter>(
"EditorComponentAdapter", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Default, &EditorComponentAdapter::m_controller, "Controller", "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorComponentAdapter::OnConfigurationChanged)
;
}
}
}
//////////////////////////////////////////////////////////////////////////
// Get*Services functions
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
AzFramework::Components::GetProvidedServicesHelper<TController>(services, typename AZ::HasComponentProvidedServices<TController>::type());
}
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
AzFramework::Components::GetRequiredServicesHelper<TController>(services, typename AZ::HasComponentRequiredServices<TController>::type());
}
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
AzFramework::Components::GetIncompatibleServicesHelper<TController>(services, typename AZ::HasComponentIncompatibleServices<TController>::type());
}
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
AzFramework::Components::GetDependentServicesHelper<TController>(services, typename AZ::HasComponentDependentServices<TController>::type());
}
//////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::BuildGameEntity(AZ::Entity* gameEntity)
{
gameEntity->CreateComponent<TRuntimeComponent>(m_controller.GetConfiguration());
}
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::Init()
{
EditorComponentBase::Init();
AzFramework::Components::ComponentInitHelper<TController>::Init(m_controller);
}
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::Activate()
{
EditorComponentBase::Activate();
if (ShouldActivateController())
{
m_controller.Activate(GetEntityId());
}
}
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::Deactivate()
{
m_controller.Deactivate();
EditorComponentBase::Deactivate();
}
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
bool EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::ReadInConfig(const AZ::ComponentConfig* baseConfig)
{
if (const auto config = azrtti_cast<const TConfiguration*>(baseConfig))
{
m_controller.SetConfiguration(*config);
return true;
}
return false;
}
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
bool EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
{
if (auto config = azrtti_cast<TConfiguration*>(outBaseConfig))
{
*config = m_controller.GetConfiguration();
return true;
}
return false;
}
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
AZ::u32 EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::OnConfigurationChanged()
{
m_controller.Deactivate();
if (ShouldActivateController())
{
m_controller.Activate(GetEntityId());
}
return AZ::Edit::PropertyRefreshLevels::None;
}
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
bool EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::ShouldActivateController() const
{
return true;
}
} // namespace Components
} // namespace AzToolsFramework
@@ -0,0 +1,129 @@
/*
* 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 "AzToolsFramework_precompiled.h"
#include "EditorComponentBase.h"
#include "TransformComponent.h"
#include "SelectionComponent.h"
#include <AzCore/Math/Vector2.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
namespace AzToolsFramework
{
namespace Components
{
void EditorComponentBase::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<EditorComponentBase, AZ::Component>()
->Version(1)
;
}
}
EditorComponentBase::EditorComponentBase()
{
m_transform = nullptr;
m_selection = nullptr;
}
void EditorComponentBase::Init()
{
}
void EditorComponentBase::Activate()
{
m_transform = GetEntity()->FindComponent<TransformComponent>();
m_selection = GetEntity()->FindComponent<SelectionComponent>();
}
void EditorComponentBase::Deactivate()
{
m_transform = nullptr;
m_selection = nullptr;
}
void EditorComponentBase::SetDirty()
{
if (GetEntity())
{
EBUS_EVENT(AzToolsFramework::ToolsApplicationRequests::Bus, AddDirtyEntity, GetEntity()->GetId());
}
else
{
AZ_Warning("Editor", false, "EditorComponentBase::SetDirty() failed. Couldn't add dirty entity because the pointer to the entity is NULL. Make sure the entity is Init()'d properly.");
}
}
AZ::TransformInterface* EditorComponentBase::GetTransform() const
{
AZ_Assert(m_transform, "Attempt to GetTransformComponent when the entity is inactive or does not have one.");
return m_transform;
}
Components::SelectionComponent* EditorComponentBase::GetSelection() const
{
AZ_Assert(m_selection, "Attempt to GetSelection when the entity is inactive or does not have one.");
return m_selection;
}
AZ::Transform EditorComponentBase::GetWorldTM() const
{
if (m_transform)
{
return m_transform->GetWorldTM();
}
else
{
return AZ::Transform::Identity();
}
}
AZ::Transform EditorComponentBase::GetLocalTM() const
{
if (m_transform)
{
return m_transform->GetLocalTM();
}
else
{
return AZ::Transform::Identity();
}
}
bool EditorComponentBase::IsSelected() const
{
if (m_selection)
{
return m_selection->IsSelected();
}
else
{
return false;
}
}
bool EditorComponentBase::IsPrimarySelection() const
{
if (m_selection)
{
return m_selection->IsPrimarySelection();
}
else
{
return false;
}
}
}
} // namespace AzToolsFramework
@@ -0,0 +1,445 @@
/*
* 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.
*
*/
/**
* @file
* Header file for the editor component base class.
* Derive from this class to create a version of a component to use in the
* editor, as opposed to the version of the component that is used during run time.
* To learn more about editor components, see the [Lumberyard Developer Guide]
* (http://docs.aws.amazon.com/lumberyard/latest/developerguide/component-entity-system-pg-editor-components.html).
*/
#ifndef EDITOR_COMPONENT_BASE_H
#define EDITOR_COMPONENT_BASE_H
#include <AzCore/base.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Math/Crc.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Component/Entity.h>
class QMenu;
namespace AZ
{
class Vector2;
}
namespace AzToolsFramework
{
namespace Components
{
class SelectionComponent;
/**
* A base class for all editor components.
* Derive from this class to create a version of a component to use in the
* editor, as opposed to the version of the component that is used during runtime.
*
* **Important:** Game components must not inherit from EditorComponentBase.
* To create one or more game components to represent your editor component
* in runtime, use BuildGameEntity().
*
* To learn more about editor components, see the [Lumberyard Developer Guide]
* (http://docs.aws.amazon.com/lumberyard/latest/developerguide/component-entity-system-pg-editor-components.html).
*/
class EditorComponentBase
: public AZ::Component
{
friend class EditorEntityActionComponent;
friend class EditorDisabledCompositionComponent;
friend class EditorPendingCompositionComponent;
public:
/**
* Adds run-time type information to the component.
*/
AZ_RTTI(EditorComponentBase, "{D5346BD4-7F20-444E-B370-327ACD03D4A0}", AZ::Component);
/**
* Creates an instance of this class.
*/
EditorComponentBase();
/**
* Sets a flag on the entire entity to indicate that the entity's properties
* were modified.
* Call this function whenever you alter an entity in an unexpected manner.
* For example, edits that you make to one entity might affect other entities,
* so the affected entities need to know that something changed.
* You do not need to call this function when editing an entity's property
* in the Property Editor, because that scenario automatically sets the flag.
* You need to call this function only when your entity's properties are
* modified outside the Property Editor, such as when a script loops over
* all lights and alters their radii.
*/
void SetDirty();
//////////////////////////////////////////////////////////////////////////
// AZ::Component
/**
* Initializes the component's resources.
* Overrides AZ::Component::Init().
*
* **Important:** %Components derived from EditorComponentBase must
* call the Init() function of the base class.
*
* (Optional) You can override this function to initialize
* resources that the component needs.
*/
virtual void Init() override;
/**
* Gets the transform component and selection component of the
* entity that the component belongs to, if the entity has them.
* Overrides AZ::Component::Activate().
*
* **Important:** %Components derived from EditorComponentBase must
* call the Activate() function of the base class.
*/
virtual void Activate() override;
/**
* Sets the component's pointers to the transform component
* and selection component to null.
* Overrides AZ::Component::Deactivate().
*
* **Important:** %Components derived from EditorComponentBase must
* call the Deactivate() function of the base class.
*/
virtual void Deactivate() override;
//////////////////////////////////////////////////////////////////////////
/**
* Gets the transform interface of the entity that the component
* belongs to, if the entity has a transform component.
* A transform positions, rotates, and scales an entity in 3D space.
* @return A pointer to the transform interface. Might be null if
* you did not include "TransformService" in the component's
* AZ::ComponentDescriptor::GetRequiredServices().
*/
AZ::TransformInterface* GetTransform() const;
/**
* Gets the selection component of the entity that the component
* belongs to, if the entity has a selection component.
* A selection component keeps track of whether the entity is
* selected in the editor.
* @return A pointer to the selection component. Might be null if
* you did not include "SelectionService" in the component's
* AZ::ComponentDescriptor::GetRequiredServices().
*/
SelectionComponent* GetSelection() const;
/**
* Gets the world transform of the entity that the component belongs
* to, if the entity has a transform component.
* An entity's world transform is the entity's position within the
* entire game space.
* @return The world transform, if the entity has one. Otherwise, returns
* the identity transform, which is the equivalent of no transform.
*/
AZ::Transform GetWorldTM() const;
/**
* Gets the local transform of the entity that the component belongs
* to, if the entity has a transform component.
* An entity's local transform is the entity's position relative to its
* parent entity.
* @return The local transform, if the entity has one. Otherwise, returns
* the identity transform, which is the equivalent of no transform.
*/
AZ::Transform GetLocalTM() const;
/**
* Identifies whether the component is selected in the editor.
* @return True if the component is selected in the editor.
* Otherwise, false.
*/
bool IsSelected() const;
/**
* Identifies whether the component is the primary selection in the editor.
* @return True if the component is the primary selection in the editor.
* Otherwise, false.
*/
bool IsPrimarySelection() const;
/// @cond EXCLUDE_DOCS
void UnregisterIcon();
/// @endcond
/**
* Determines if the entity that the component belongs to
* has a selection component.
* A selection component keeps track of whether the entity is
* selected in the editor.
* @return True if the entity has a selection component.
* Otherwise, false.
*/
bool HasSelectionComponent() const { return m_selection != nullptr; }
/**
* Override this function to create one or more game components
* to represent your editor component in runtime.
*
* **Important:** If your entity has a game component, you must implement this function.
*
* This function is called by the slice builder. Any game components
* that you create should be attached to the game entity that is
* provided to this function. If you do not need to create a game
* component, you do not need to override this function.
* The provided component to the gameEntity is dynamically generated and owned by the
* gameEntity and should be deallocated appropriately.
* @param gameEntity A pointer to the game entity.
*/
virtual void BuildGameEntity(AZ::Entity* /*gameEntity*/) {}
/**
* Implement this function to support dragging and dropping an asset
* onto this component.
* @param assetId A reference to the ID of the asset to drag and drop.
*/
virtual void SetPrimaryAsset(const AZ::Data::AssetId& /*assetId*/) { }
/**
* Implement this to add component specific context menu options to your editor component
* when right clicked in the entity inspector
*/
virtual void AddContextMenuActions(QMenu* /*menu*/) {}
/**
* Reflects component data into a variety of contexts (script, serialize,
* edit, and so on).
* @param context A pointer to the reflection context.
*/
static void Reflect(AZ::ReflectContext* context);
private:
AZ::TransformInterface* m_transform;
SelectionComponent* m_selection;
};
/// @cond EXCLUDE_DOCS
/**
* Interface for AzToolsFramework::Components::EditorComponentDescriptorBus,
* which handles requests to the editor component regarding editor-only functionality.
* Do not assume that all editor components have it.
*/
class EditorComponentDescriptor
{
public:
/**
* Checks the equality of components.
*
* If you want your component to have a custom DoComponentsMatch()
* function, you need to do the following:
* - Put the AZ_EDITOR_COMPONENT macro in your class, instead of AZ_COMPONENT.
* - Define a static DoComponentsMatch() function with the following signature:
*
* `bool DoComponentsMatch(const ComponentClass*, const ComponentClass*); // where ComponentClass is the type of the class containing this function.`
*
* For example, ScriptComponents have a custom DoComponentsMatch() function
* so that two ScriptComponents, which are in C++, are determined to be equal
* only if they use the same Lua file to define their behavior.
*
* @param thisComponent The first component to compare.
* @param otherComponent The component to compare with the first component.
* @return True if the components are the same. Otherwise, false.
*/
virtual bool DoComponentsMatch(const AZ::Component* thisComponent, const AZ::Component* otherComponent) const = 0;
/**
* Allows a "paste-over" operation on this component.
*
* If you want to allow this functionality on your component, you need to
* do the following:
* - Put the AZ_EDITOR_COMPONENT macro in your class, instead of AZ_COMPONENT.
* - Define a static PasteOverComponent() function with the following signature:
*
* `void PasteOverComponent(const ComponentClass* sourceComponent, ComponentClass* destinationComponent); // where ComponentClass is the type of the class containing this function.`
*
* @param sourceComponent The component to pull data from.
* @param destinationComponent The component to apply the paste operation to.
*/
virtual void PasteOverComponent(const AZ::Component* sourceComponent, AZ::Component* destinationComponent) = 0;
/**
* Checks if "paste-over" is supported on this component.
*
* @return True if the component this is describing implements PasteOverComponent.
*/
virtual bool SupportsPasteOver() const = 0;
/**
* Returns the editor component descriptor of the current component.
* @return A pointer to the editor component descriptor.
*/
virtual EditorComponentDescriptor* GetEditorDescriptor() { return this; }
};
/**
* The properties of the editor component descriptor EBus.
*/
using EditorComponentDescriptorBusTraits = AZ::ComponentDescriptorBusTraits;
/**
* An EBus for requests to the editor component.
* The events are defined in the AzToolsFramework::Components::EditorComponentDescriptor class.
*/
using EditorComponentDescriptorBus = AZ::EBus<EditorComponentDescriptor, EditorComponentDescriptorBusTraits>;
/**
* The default editor component descriptor. The editor component descriptor is the
* interface for AzToolsFramework::Components::EditorComponentDescriptorBus,
* which handles requests to the component regarding editor-only functionality.
* @tparam ComponentClass The type of component.
*/
template <class ComponentClass>
class EditorComponentDescriptorDefault
: public AZ::ComponentDescriptorDefault<ComponentClass>
, public EditorComponentDescriptorBus::Handler
{
public:
/**
* Specifies that this class should use AZ::SystemAllocator for memory
* management by default.
*/
AZ_CLASS_ALLOCATOR(EditorComponentDescriptorDefault<ComponentClass>, AZ::SystemAllocator, 0);
AZ_HAS_STATIC_MEMBER(EditorComponentMatching, DoComponentsMatch, bool, (const ComponentClass* thisComponent, const ComponentClass* otherComponent));
AZ_HAS_STATIC_MEMBER(EditorComponentPasteOver, PasteOverComponent, void, (const ComponentClass* sourceComponent, ComponentClass* destinationComponent));
/**
* Creates an instance of this class.
*/
EditorComponentDescriptorDefault()
{
EditorComponentDescriptorBus::Handler::BusConnect(AZ::AzTypeInfo<ComponentClass>::Uuid());
}
~EditorComponentDescriptorDefault()
{
EditorComponentDescriptorBus::Handler::BusDisconnect();
}
/**
* Checks whether two components are the same.
* @param thisComponent The first component to compare.
* @param otherComponent The component to compare with the first component.
* @return True if the components are the same. Otherwise, false.
*/
bool DoComponentsMatch(const AZ::Component* thisComponent, const AZ::Component* otherComponent) const override
{
auto thisActualComponent = azrtti_cast<const ComponentClass*>(thisComponent);
AZ_Assert(thisActualComponent, "Used the wrong descriptor to check if components match");
auto otherActualComponent = azrtti_cast<const ComponentClass*>(otherComponent);
if (!otherActualComponent)
{
return false;
}
return CallDoComponentsMatch(thisActualComponent, otherActualComponent, typename HasEditorComponentMatching<ComponentClass>::type());
}
/**
* Pastes over another component, copying desired data from sourceComponent to destinationComponent.
*
* @param sourceComponent The component to pull data from.
* @param destinationComponent The component to apply the paste operation to.
*/
void PasteOverComponent(const AZ::Component* sourceComponent, AZ::Component* destinationComponent) override
{
auto sourceActualComponent = azrtti_cast<const ComponentClass*>(sourceComponent);
AZ_Assert(sourceActualComponent, "Used the wrong descriptor to attempt a paste over operation");
auto destinationActualComponent = azrtti_cast<ComponentClass*>(destinationComponent);
if (!destinationActualComponent)
{
return;
}
CallPasteOverComponent(sourceActualComponent, destinationActualComponent, typename HasEditorComponentPasteOver<ComponentClass>::type());
}
/**
* Checks if "paste-over" is supported on this component.
*
* @return True if the component this is describing implements PasteOverComponent.
*/
bool SupportsPasteOver() const override
{
return HasEditorComponentPasteOver<ComponentClass>::value;
}
private:
bool CallDoComponentsMatch(const ComponentClass* thisComponent, const ComponentClass* otherComponent, const AZStd::true_type&) const
{
return ComponentClass::DoComponentsMatch(thisComponent, otherComponent);
}
bool CallDoComponentsMatch(const ComponentClass* /*thisComponent*/, const ComponentClass* /*outerComponent*/, const AZStd::false_type&) const
{
return true;
}
void CallPasteOverComponent(const ComponentClass* sourceComponent, ComponentClass* destinationComponent, const AZStd::true_type&)
{
ComponentClass::PasteOverComponent(sourceComponent, destinationComponent);
}
void CallPasteOverComponent(const ComponentClass* /*sourceComponent*/, ComponentClass* /*destinationComponent*/, const AZStd::false_type&)
{
}
};
/**
* Declares an editor component descriptor class.
* Unless you are implementing very advanced internal functionality, we recommend
* using AZ_EDITOR_COMPONENT instead of this macro. You can use this macro to implement
* a static function in the component class instead of writing a descriptor. It defines
* a CreateDescriptorFunction that you can call to register a descriptor.
* (Only one descriptor can exist per environment.) This macro fails silently if you
* implement the functions with the wrong signatures.
*/
#define AZ_EDITOR_COMPONENT_INTRUSIVE_DESCRIPTOR_TYPE(_ComponentClass) \
friend class AZ::ComponentDescriptorDefault<_ComponentClass>; \
friend class AzToolsFramework::Components::EditorComponentDescriptorDefault<_ComponentClass>; \
typedef AzToolsFramework::Components::EditorComponentDescriptorDefault<_ComponentClass> DescriptorType;
/**
* Declares an editor component with the default settings.
* The component derives from AzToolsFramework::Components::EditorComponentBase,
* is not templated, uses AZ::SystemAllocator, and so on.
* AZ_EDITOR_COMPONENT(_ComponentClass, _ComponentId, OtherBaseClasses... EditorComponentBase)
* is included automatically.
* @note Editor components use a separate descriptor than the underlying component system.
*/
#define AZ_EDITOR_COMPONENT(_ComponentClass, ...) \
AZ_RTTI(_ComponentClass, __VA_ARGS__, AzToolsFramework::Components::EditorComponentBase)\
AZ_EDITOR_COMPONENT_INTRUSIVE_DESCRIPTOR_TYPE(_ComponentClass) \
AZ_COMPONENT_BASE(_ComponentClass, __VA_ARGS__);
/// @endcond
} // namespace Components
} // namespace AzToolsFramework
#endif
@@ -0,0 +1,29 @@
/*
* 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 <AzCore/Component/ComponentBus.h>
#include <AzCore/Component/Component.h>
namespace AzToolsFramework
{
class EditorDisabledCompositionRequests
: public AZ::ComponentBus
{
public:
virtual void GetDisabledComponents(AZStd::vector<AZ::Component*>& components) = 0;
virtual void AddDisabledComponent(AZ::Component* componentToAdd) = 0;
virtual void RemoveDisabledComponent(AZ::Component* componentToRemove) = 0;
};
using EditorDisabledCompositionRequestBus = AZ::EBus<EditorDisabledCompositionRequests>;
} // namespace AzToolsFramework
@@ -0,0 +1,115 @@
/*
* 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 "AzToolsFramework_precompiled.h"
#include "EditorDisabledCompositionComponent.h"
#include <AzCore/Serialization/EditContext.h>
namespace AzToolsFramework
{
namespace Components
{
void EditorDisabledCompositionComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorDisabledCompositionComponent, EditorComponentBase>()
->Field("DisabledComponents", &EditorDisabledCompositionComponent::m_disabledComponents)
;
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<EditorDisabledCompositionComponent>("Disabled Components", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide)
->Attribute(AZ::Edit::Attributes::HideIcon, true)
->Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::HideOnAdd | AZ::Edit::SliceFlags::PushWhenHidden)
;
}
}
}
void EditorDisabledCompositionComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("EditorDisabledCompositionService", 0x277e3445));
}
void EditorDisabledCompositionComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("EditorDisabledCompositionService", 0x277e3445));
}
void EditorDisabledCompositionComponent::GetDisabledComponents(AZStd::vector<AZ::Component*>& components)
{
components.insert(components.end(), m_disabledComponents.begin(), m_disabledComponents.end());
}
void EditorDisabledCompositionComponent::AddDisabledComponent(AZ::Component* componentToAdd)
{
AZ_Assert(componentToAdd, "Unable to add a disabled component that is nullptr");
if (componentToAdd && AZStd::find(m_disabledComponents.begin(), m_disabledComponents.end(), componentToAdd) == m_disabledComponents.end())
{
m_disabledComponents.push_back(componentToAdd);
}
}
void EditorDisabledCompositionComponent::RemoveDisabledComponent(AZ::Component* componentToRemove)
{
AZ_Assert(componentToRemove, "Unable to remove a disabled component that is nullptr");
if (componentToRemove)
{
m_disabledComponents.erase(AZStd::remove(m_disabledComponents.begin(), m_disabledComponents.end(), componentToRemove), m_disabledComponents.end());
}
};
EditorDisabledCompositionComponent::~EditorDisabledCompositionComponent()
{
for (auto disabledComponent : m_disabledComponents)
{
delete disabledComponent;
}
m_disabledComponents.clear();
// We disconnect from the bus here because we need to be able to respond even if the entity and component are not active
// This is a special case for certain EditorComponents only!
EditorDisabledCompositionRequestBus::Handler::BusDisconnect();
}
void EditorDisabledCompositionComponent::Init()
{
EditorComponentBase::Init();
// We connect to the bus here because we need to be able to respond even if the entity and component are not active
// This is a special case for certain EditorComponents only!
EditorDisabledCompositionRequestBus::Handler::BusConnect(GetEntityId());
// Set the entity* for each disabled component
for (auto disabledComponent : m_disabledComponents)
{
auto editorComponentBaseComponent = azrtti_cast<Components::EditorComponentBase*>(disabledComponent);
AZ_Assert(editorComponentBaseComponent, "Editor component does not derive from EditorComponentBase");
editorComponentBaseComponent->SetEntity(GetEntity());
}
}
void EditorDisabledCompositionComponent::Activate()
{
EditorComponentBase::Activate();
}
void EditorDisabledCompositionComponent::Deactivate()
{
EditorComponentBase::Deactivate();
}
} // namespace Components
} // namespace AzToolsFramework
@@ -0,0 +1,52 @@
/*
* 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 "EditorComponentBase.h"
#include "EditorDisabledCompositionBus.h"
namespace AzToolsFramework
{
namespace Components
{
/**
* Contains Disabled components to be added to the entity we are attached to.
*/
class EditorDisabledCompositionComponent
: public AzToolsFramework::Components::EditorComponentBase
, public EditorDisabledCompositionRequestBus::Handler
{
public:
AZ_COMPONENT(EditorDisabledCompositionComponent, "{E77AE6AC-897D-4035-8353-637449B6DCFB}", EditorComponentBase);
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
////////////////////////////////////////////////////////////////////
// EditorDisabledCompositionRequestBus
void GetDisabledComponents(AZStd::vector<AZ::Component*>& components) override;
void AddDisabledComponent(AZ::Component* componentToAdd) override;
void RemoveDisabledComponent(AZ::Component* componentToRemove) override;
////////////////////////////////////////////////////////////////////
~EditorDisabledCompositionComponent() override;
private:
////////////////////////////////////////////////////////////////////
// AZ::Entity
void Init() override;
void Activate() override;
void Deactivate() override;
////////////////////////////////////////////////////////////////////
AZStd::vector<AZ::Component*> m_disabledComponents;
};
} // namespace Components
} // namespace AzToolsFramework
@@ -0,0 +1,324 @@
/*
* 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 "AzToolsFramework_precompiled.h"
#include "EditorEntityIconComponent.h"
#include <AzCore/RTTI/TypeInfo.h>
#include <AzCore/Asset/AssetManagerBus.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/ToolsComponents/EditorVisibilityBus.h>
#include <AzToolsFramework/ToolsComponents/GenericComponentWrapper.h>
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
namespace AzToolsFramework
{
namespace Components
{
void EditorEntityIconComponent::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<EditorEntityIconComponent, EditorComponentBase>()
->Field("EntityIconAssetId", &EditorEntityIconComponent::m_entityIconAssetId)
;
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<EditorEntityIconComponent>("Entity Icon", "Edit-time entity icon in entity-inspector and viewport")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide)
->Attribute(AZ::Edit::Attributes::HideIcon, true)
->Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::HideOnAdd | AZ::Edit::SliceFlags::PushWhenHidden)
;
}
}
}
void EditorEntityIconComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("EditorEntityIconService", 0x94dff5d7));
}
void EditorEntityIconComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("EditorEntityIconService", 0x94dff5d7));
}
EditorEntityIconComponent::~EditorEntityIconComponent()
{
}
void EditorEntityIconComponent::Init()
{
EditorComponentBase::Init();
}
void EditorEntityIconComponent::Activate()
{
EditorComponentBase::Activate();
AZ::EntityBus::Handler::BusConnect(GetEntityId());
EditorEntityIconComponentRequestBus::Handler::BusConnect(GetEntityId());
EditorInspectorComponentNotificationBus::Handler::BusConnect(GetEntityId());
}
void EditorEntityIconComponent::Deactivate()
{
EditorInspectorComponentNotificationBus::Handler::BusDisconnect();
EditorEntityIconComponentRequestBus::Handler::BusDisconnect();
AZ::EntityBus::Handler::BusDisconnect();
EditorComponentBase::Deactivate();
}
void EditorEntityIconComponent::SetEntityIconAsset(const AZ::Data::AssetId& assetId)
{
if (m_entityIconAssetId != assetId)
{
m_entityIconAssetId = assetId;
m_entityIconCache.SetEntityIconPath(CalculateEntityIconPath(m_firstComponentIdCache));
EditorEntityIconComponentNotificationBus::Event(GetEntityId(), &EditorEntityIconComponentNotificationBus::Events::OnEntityIconChanged, m_entityIconAssetId);
SetDirty();
}
}
AZ::Data::AssetId EditorEntityIconComponent::GetEntityIconAssetId()
{
return m_entityIconAssetId;
}
AZStd::string EditorEntityIconComponent::GetEntityIconPath()
{
if (m_entityIconCache.Empty())
{
UpdateFirstComponentIdCache();
m_entityIconCache.SetEntityIconPath(CalculateEntityIconPath(m_firstComponentIdCache));
}
return m_entityIconCache.GetEntityIconPath();
}
int EditorEntityIconComponent::GetEntityIconTextureId()
{
return m_entityIconCache.GetEntityIconTextureId();
}
bool EditorEntityIconComponent::IsEntityIconHiddenInViewport()
{
return (!m_entityIconAssetId.IsValid() && m_preferNoViewportIcon);
}
void EditorEntityIconComponent::OnEntityActivated(const AZ::EntityId&)
{
if (m_entityIconCache.Empty())
{
/* The case where the entity is activated the first time. */
UpdatePreferNoViewportIconFlag();
UpdateFirstComponentIdCache();
m_entityIconCache.SetEntityIconPath(CalculateEntityIconPath(m_firstComponentIdCache));
EditorEntityIconComponentNotificationBus::Event(GetEntityId(), &EditorEntityIconComponentNotificationBus::Events::OnEntityIconChanged, m_entityIconAssetId);
}
}
void EditorEntityIconComponent::OnComponentOrderChanged()
{
if (!m_entityIconAssetId.IsValid())
{
const bool preferNoViewportIconFlagChanged = UpdatePreferNoViewportIconFlag();
const bool firstComponentIdChanged = UpdateFirstComponentIdCache();
if (firstComponentIdChanged)
{
m_entityIconCache.SetEntityIconPath(GetDefaultEntityIconPath(m_firstComponentIdCache));
EditorEntityIconComponentNotificationBus::Event(GetEntityId(), &EditorEntityIconComponentNotificationBus::Events::OnEntityIconChanged, m_entityIconAssetId);
}
else if (preferNoViewportIconFlagChanged)
{
EditorEntityIconComponentNotificationBus::Event(GetEntityId(), &EditorEntityIconComponentNotificationBus::Events::OnEntityIconChanged, m_entityIconAssetId);
}
}
}
AZStd::string EditorEntityIconComponent::CalculateEntityIconPath(AZ::ComponentId firstComponentId)
{
AZStd::string entityIconPath = GetEntityIconAssetPath();
if (entityIconPath.empty())
{
entityIconPath = GetDefaultEntityIconPath(firstComponentId);
}
return entityIconPath;
}
AZStd::string EditorEntityIconComponent::GetEntityIconAssetPath()
{
bool foundIcon = false;
AZStd::string entityIconPath;
if (m_entityIconAssetId.IsValid())
{
AZ::Data::AssetInfo iconAssetInfo;
AZ::Data::AssetCatalogRequestBus::BroadcastResult(iconAssetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, m_entityIconAssetId);
if (iconAssetInfo.m_assetType != AZ::Data::s_invalidAssetType)
{
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(foundIcon, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, iconAssetInfo.m_relativePath, entityIconPath);
}
}
if (foundIcon)
{
return entityIconPath;
}
else
{
return AZStd::string();
}
}
AZStd::string EditorEntityIconComponent::GetDefaultEntityIconPath(AZ::ComponentId firstComponentId)
{
AZStd::string entityIconPath;
if (firstComponentId != AZ::InvalidComponentId)
{
AZ::Entity* entity = GetEntity();
if (entity)
{
AZ::Component* component = entity->FindComponent(firstComponentId);
if (component)
{
AZ::Uuid componentType = AzToolsFramework::GetUnderlyingComponentType(*component);
AzToolsFramework::EditorRequestBus::BroadcastResult(entityIconPath, &AzToolsFramework::EditorRequestBus::Events::GetComponentIconPath, componentType, AZ::Edit::Attributes::ViewportIcon, component);
}
}
}
if (entityIconPath.empty())
{
AzToolsFramework::EditorRequestBus::BroadcastResult(entityIconPath, &AzToolsFramework::EditorRequestBus::Events::GetDefaultEntityIcon);
}
return entityIconPath;
}
bool EditorEntityIconComponent::UpdateFirstComponentIdCache()
{
bool firstComponentIdChanged = false;
ComponentOrderArray componentOrderArray;
EditorInspectorComponentRequestBus::EventResult(componentOrderArray, GetEntityId(), &EditorInspectorComponentRequests::GetComponentOrderArray);
if (componentOrderArray.empty())
{
if (m_firstComponentIdCache != AZ::InvalidComponentId)
{
m_firstComponentIdCache = AZ::InvalidComponentId;
firstComponentIdChanged = true;
}
}
else
{
if (componentOrderArray.size() > 1)
{
if (m_firstComponentIdCache != componentOrderArray[1])
{
m_firstComponentIdCache = componentOrderArray[1];
firstComponentIdChanged = true;
}
}
else if(m_firstComponentIdCache != componentOrderArray.front())
{
m_firstComponentIdCache = componentOrderArray.front();
firstComponentIdChanged = true;
}
}
return firstComponentIdChanged;
}
bool EditorEntityIconComponent::UpdatePreferNoViewportIconFlag()
{
bool flagChanged = false;
ComponentOrderArray componentOrderArray;
EditorInspectorComponentRequestBus::EventResult(componentOrderArray, GetEntityId(), &EditorInspectorComponentRequests::GetComponentOrderArray);
if (componentOrderArray.empty())
{
if (m_preferNoViewportIcon == true)
{
m_preferNoViewportIcon = false;
flagChanged = true;
}
}
else
{
bool preferNoViewportIcon = false;
AZ::SerializeContext* serializeContext = nullptr;
EBUS_EVENT_RESULT(serializeContext, AZ::ComponentApplicationBus, GetSerializeContext);
AZ_Assert(serializeContext, "No serialize context");
for (AZ::ComponentId componentId : componentOrderArray)
{
AZ::Entity* entity = GetEntity();
AZ::Component* component = entity->FindComponent(componentId);
if (component == nullptr)
{
continue;
}
AZ::Uuid componentType = AzToolsFramework::GetUnderlyingComponentType(*component);
auto classData = serializeContext->FindClassData(componentType);
if (classData && classData->m_editData)
{
auto editorElementData = classData->m_editData->FindElementData(AZ::Edit::ClassElements::EditorData);
if (editorElementData)
{
if (auto preferNoViewportIconAttribute = editorElementData->FindAttribute(AZ::Edit::Attributes::PreferNoViewportIcon))
{
auto preferNoViewportIconAttributeData = azdynamic_cast<const AZ::Edit::AttributeData<bool>*>(preferNoViewportIconAttribute);
if (preferNoViewportIconAttributeData)
{
if (preferNoViewportIconAttributeData->Get(nullptr))
{
preferNoViewportIcon = true;
break;
}
}
}
}
}
}
if (m_preferNoViewportIcon != preferNoViewportIcon)
{
m_preferNoViewportIcon = preferNoViewportIcon;
flagChanged = true;
}
}
return flagChanged;
}
int EditorEntityIconComponent::EntityIcon::GetEntityIconTextureId()
{
// if we do not yet have a valid texture id, request it using the entity icon path
if (m_entityIconTextureId == 0)
{
EditorRequestBus::BroadcastResult(
m_entityIconTextureId, &EditorRequests::GetIconTextureIdFromEntityIconPath, m_entityIconPath);
}
return m_entityIconTextureId;
}
} // namespace Components
} // namespace AzToolsFramework
@@ -0,0 +1,112 @@
/*
* 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 <AzCore/Component/EntityBus.h>
#include "EditorComponentBase.h"
#include "EditorEntityIconComponentBus.h"
#include "EditorInspectorComponentBus.h"
namespace AzToolsFramework
{
namespace Components
{
/// Entity icons are the visual icon representing an entity in the editor viewport.
/// This component enables customization of the entity icon for the owning entity.
/// If the \ref m_entityIconAssetId is invalid, an icon from one of its components is chosen instead.
class EditorEntityIconComponent
: public EditorComponentBase
, public AZ::EntityBus::Handler
, public EditorEntityIconComponentRequestBus::Handler
, public EditorInspectorComponentNotificationBus::Handler
{
public:
AZ_COMPONENT(EditorEntityIconComponent, "{E15D42C2-912D-466F-9547-E7E948CE2D7D}", EditorComponentBase);
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
~EditorEntityIconComponent() override;
private:
/// Wrap dependent icon path and icon texture id to ensure
/// they remain in a consistent state.
class EntityIcon
{
public:
const AZStd::string& GetEntityIconPath() const
{
return m_entityIconPath;
}
void SetEntityIconPath(const AZStd::string& entityIconPath)
{
m_entityIconPath = entityIconPath;
m_entityIconTextureId = 0;
}
bool Empty() const
{
return m_entityIconPath.empty();
}
/// Return the texture id (of a particular component) for this entity.
/// @note Looked up from entityIconPath.
int GetEntityIconTextureId();
private:
AZStd::string m_entityIconPath; ///< Store the component icon path for the entity.
int m_entityIconTextureId = 0; ///< Store the texture id for the component icon.
};
// AZ::Entity
void Init() override;
void Activate() override;
void Deactivate() override;
// EditorEntityIconComponentRequestBus
void SetEntityIconAsset(const AZ::Data::AssetId& assetId) override;
AZ::Data::AssetId GetEntityIconAssetId() override;
AZStd::string GetEntityIconPath() override;
int GetEntityIconTextureId() override;
bool IsEntityIconHiddenInViewport() override;
// EntityBus
void OnEntityActivated(const AZ::EntityId&) override;
// EditorInspectorComponentNotificationBus
void OnComponentOrderChanged() override;
/// Return the path of the entity icon asset identified by \ref m_entityIconAssetId if it's valid,
/// else return the path of the icon of the first component in this entity's EditorInspector list,
/// otherwise return the path of the default entity icon.
AZStd::string CalculateEntityIconPath(AZ::ComponentId firstComponentId);
AZStd::string GetEntityIconAssetPath();
AZStd::string GetDefaultEntityIconPath(AZ::ComponentId firstComponentId);
/// Return a boolean indicating if \ref m_firstComponentIdCache has been changed.
bool UpdateFirstComponentIdCache();
bool UpdatePreferNoViewportIconFlag();
AZ::Data::AssetId m_entityIconAssetId = AZ::Data::AssetId();
EntityIcon m_entityIconCache; ///< The cached entity icon path and texture id.
AZ::ComponentId m_firstComponentIdCache = AZ::InvalidComponentId; ///< First component id listed in the EntityInspector,
///< excluding any default components such as TransformComponent.
bool m_preferNoViewportIcon = false; ///< Indicates if any component of this entity
///< has the PreferNoViewportIcon Edit Attribute.
};
}
}
@@ -0,0 +1,74 @@
/*
* 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 <AzCore/Component/ComponentBus.h>
#include <AzCore/std/string/string.h>
#include <AzCore/Asset/AssetCommon.h>
namespace AzToolsFramework
{
/**
* EBus calls for setting / getting information about the entity icon.
*/
class EditorEntityIconComponentRequests
: public AZ::ComponentBus
{
public:
/**
* Set entity icon by assigning an Entity Icon Asset.
*/
virtual void SetEntityIconAsset(const AZ::Data::AssetId& assetId) = 0;
/**
* Get the entity icon asset id.
* If the returned asset id is invalid, an icon of one of the entity's components will be used instead.
*/
virtual AZ::Data::AssetId GetEntityIconAssetId() = 0;
/**
* Get the full path of the source icon image associated with the current entity.
*/
virtual AZStd::string GetEntityIconPath() = 0;
/**
* Get the texture id of this entity icon.
* The Id is used to lookup the texture in the graphics system.
*/
virtual int GetEntityIconTextureId() = 0;
/**
* Get the hide flag for the entity icon in viewport.
* @return A boolean denoting whether the entity icon should be hidden in viewport.
*/
virtual bool IsEntityIconHiddenInViewport() = 0;
};
using EditorEntityIconComponentRequestBus = AZ::EBus<EditorEntityIconComponentRequests>;
/**
* EBus events about entity icon.
*/
class EditorEntityIconComponentNotifications
: public AZ::ComponentBus
{
public:
/**
* EBus events fired when an entity's icon changed.
*/
virtual void OnEntityIconChanged(const AZ::Data::AssetId& entityIconAssetId) = 0;
};
using EditorEntityIconComponentNotificationBus = AZ::EBus<EditorEntityIconComponentNotifications>;
}
@@ -0,0 +1,69 @@
/*
* 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 "AzToolsFramework_precompiled.h"
#include "EditorEntityIdContainer.h"
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Serialization/ObjectStream.h>
#include <AzCore/Serialization/Utils.h>
#include <AzCore/IO/GenericStreams.h>
#include <AzCore/IO/ByteContainerStream.h>
#include <QString>
namespace AzToolsFramework
{
const QString& EditorEntityIdContainer::GetMimeType()
{
static QString mimeType = QStringLiteral("editor/entityidlist");
return mimeType;
}
void EditorEntityIdContainer::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<EditorEntityIdContainer>()
->Field("m_entityIds", &EditorEntityIdContainer::m_entityIds)
->Version(1);
}
}
bool EditorEntityIdContainer::ToBuffer(AZStd::vector<char>& buffer)
{
buffer.clear();
AZ::IO::ByteContainerStream<AZStd::vector<char> > ms(&buffer);
return AZ::Utils::SaveObjectToStream(ms, AZ::DataStream::ST_BINARY, this);
}
bool EditorEntityIdContainer::FromBuffer(const char* data, AZStd::size_t size)
{
AZ::IO::MemoryStream ms(data, size);
EditorEntityIdContainer* pContainer = AZ::Utils::LoadObjectFromStream<EditorEntityIdContainer>(ms, nullptr);
if (pContainer)
{
m_entityIds = AZStd::move(pContainer->m_entityIds);
delete pContainer;
return true;
}
return false;
}
bool EditorEntityIdContainer::FromBuffer(const AZStd::vector<char>& buffer)
{
return FromBuffer(buffer.data(), buffer.size());
}
}
@@ -0,0 +1,51 @@
/*
* 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.
*
*/
#ifndef EDITOR_ENTITY_ID_CONTAINER_H
#define EDITOR_ENTITY_ID_CONTAINER_H
#include <AzCore/base.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/Component/EntityId.h>
class QString;
namespace AZ
{
struct ClassDataReflection;
}
namespace AzToolsFramework
{
class EditorEntityIdContainer
{
public:
virtual ~EditorEntityIdContainer() { }
AZ_RTTI(EditorEntityIdContainer, "{22F4C72A-8ADD-49B3-884C-30C7F254AAC6}");
AZ_CLASS_ALLOCATOR(EditorEntityIdContainer, AZ::SystemAllocator, 0);
static const QString& GetMimeType();
AZStd::vector< AZ::EntityId > m_entityIds;
// utility functions to serialize/deserialize.
bool ToBuffer(AZStd::vector<char>& buffer);
bool FromBuffer(const AZStd::vector<char>& buffer);
bool FromBuffer(const char* data, AZStd::size_t size);
static void Reflect(AZ::ReflectContext* context);
};
}
#endif // EDITOR_ENTITY_ID_LIST_CONTAINER_H
@@ -0,0 +1,197 @@
/*
* 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 "EditorInspectorComponent.h"
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/std/sort.h>
namespace AzToolsFramework
{
namespace Components
{
void EditorInspectorComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<ComponentOrderEntry>()
// Persistent IDs for this are simply the component id
->PersistentId([](const void* instance) -> AZ::u64
{
return reinterpret_cast<const ComponentOrderEntry*>(instance)->m_componentId;
})
->Version(1)
->Field("ComponentId", &ComponentOrderEntry::m_componentId)
->Field("SortIndex", &ComponentOrderEntry::m_sortIndex);
serializeContext->Class<EditorInspectorComponent, EditorComponentBase>()
->Version(2, &SerializationConverter)
->EventHandler<ComponentOrderSerializationEvents>()
->Field("ComponentOrderEntryArray", &EditorInspectorComponent::m_componentOrderEntryArray);
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<EditorInspectorComponent>("Inspector Component Order", "Edit-time entity inspector state")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide)
->Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::HideOnAdd | AZ::Edit::SliceFlags::PushWhenHidden)
->Attribute(AZ::Edit::Attributes::HideIcon, true)
;
}
}
}
void EditorInspectorComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("EditorInspectorService", 0xc7357f25));
}
void EditorInspectorComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("EditorInspectorService", 0xc7357f25));
}
bool EditorInspectorComponent::SerializationConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
{
// Prior to version 2, we left the version unspecified so it was technically 0
if (classElement.GetVersion() <= 1)
{
// Convert the vector of component ids to an array of order entries
auto componentOrderArrayElement = classElement.FindSubElement(AZ_CRC("ComponentOrderArray", 0x22bd99f7));
if (!componentOrderArrayElement)
{
return false;
}
ComponentOrderArray componentOrderArray;
componentOrderArray.reserve(componentOrderArrayElement->GetNumSubElements());
AZ::ComponentId componentId;
for (int arrayElementIndex = 0; arrayElementIndex < componentOrderArrayElement->GetNumSubElements(); ++arrayElementIndex)
{
AZ::SerializeContext::DataElementNode& elementNode = componentOrderArrayElement->GetSubElement(arrayElementIndex);
if (elementNode.GetData(componentId))
{
componentOrderArray.push_back(componentId);
}
}
AZ_Error("EditorInspectorComponent", componentOrderArray.size() == componentOrderArrayElement->GetNumSubElements(), "Unable to get all the expected elements for the old component order array");
// Get rid of the old array
classElement.RemoveElementByName(AZ_CRC("ComponentOrderArray", 0x22bd99f7));
// Add a new empty array (unable to use AddElementWithData, fails stating that AZStd::vector is not registered)
int newArrayElementIndex = classElement.AddElement<ComponentOrderEntryArray>(context, "ComponentOrderEntryArray");
if (newArrayElementIndex == -1)
{
return false;
}
auto& newArrayElement = classElement.GetSubElement(newArrayElementIndex);
bool elementAddSucceeded = true;
for (size_t componentIndex = 0; componentIndex < componentOrderArray.size(); ++componentIndex)
{
int orderEntryElement = newArrayElement.AddElementWithData<ComponentOrderEntry>(context, "element", ComponentOrderEntry{componentOrderArray[componentIndex], componentIndex});
if (orderEntryElement == -1)
{
elementAddSucceeded = false;
}
}
return elementAddSucceeded;
}
return true;
}
EditorInspectorComponent::~EditorInspectorComponent()
{
// We disconnect from the bus here because we need to be able to respond even if the entity and component are not active
// This is a special case for certain EditorComponents only!
EditorInspectorComponentRequestBus::Handler::BusDisconnect();
}
void EditorInspectorComponent::Init()
{
// We connect to the bus here because we need to be able to respond even if the entity and component are not active
// This is a special case for certain EditorComponents only!
EditorInspectorComponentRequestBus::Handler::BusConnect(GetEntityId());
}
void EditorInspectorComponent::PrepareSave()
{
// If we didn't dirty the component order, we do not need to regenerate the serialized entry array
if (!m_componentOrderIsDirty)
{
return;
}
// Clear the actual persistent id storage to get rebuilt from the order entry array
m_componentOrderEntryArray.clear();
m_componentOrderEntryArray.reserve(m_componentOrderArray.size());
// Write our vector data back to the order element array
for (size_t componentIndex = 0; componentIndex < m_componentOrderArray.size(); ++componentIndex)
{
m_componentOrderEntryArray.push_back({ m_componentOrderArray[componentIndex], componentIndex });
}
m_componentOrderIsDirty = false;
}
void EditorInspectorComponent::PostLoad()
{
// Clear out the vector to be rebuilt from persistent id
m_componentOrderArray.clear();
m_componentOrderArray.reserve(m_componentOrderEntryArray.size());
// This will sort all the component order entries by sort index (primary) and component id (secondary) which should never result in any collisions
// This is used since slice data patching may create duplicate entries for the same sort index, missing indices and the like.
// It should never result in multiple component id entries since the serialization of this data uses a persistent id which is the component id
AZStd::sort(m_componentOrderEntryArray.begin(), m_componentOrderEntryArray.end(),
[](const ComponentOrderEntry& lhs, const ComponentOrderEntry& rhs) -> bool
{
return lhs.m_sortIndex < rhs.m_sortIndex || (lhs.m_sortIndex == rhs.m_sortIndex && lhs.m_componentId < rhs.m_componentId);
}
);
for (auto& componentOrderEntry : m_componentOrderEntryArray)
{
m_componentOrderArray.push_back(componentOrderEntry.m_componentId);
}
m_componentOrderIsDirty = false;
}
ComponentOrderArray EditorInspectorComponent::GetComponentOrderArray()
{
return m_componentOrderArray;
}
void EditorInspectorComponent::SetComponentOrderArray(const ComponentOrderArray& componentOrderArray)
{
if (m_componentOrderArray == componentOrderArray)
{
return;
}
m_componentOrderArray = componentOrderArray;
SetDirty();
// mark the order as dirty before sending the OnComponentOrderChanged event in order for PrepareSave to be properly handled in the case
// one of the event listeners needs to build the InstanceDataHierarchy
m_componentOrderIsDirty = true;
EditorInspectorComponentNotificationBus::Event(GetEntityId(), &EditorInspectorComponentNotificationBus::Events::OnComponentOrderChanged);
}
} // namespace Components
} // namespace AzToolsFramework
@@ -0,0 +1,106 @@
/*
* 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 "EditorComponentBase.h"
#include "EditorInspectorComponentBus.h"
#include <AzCore/Serialization/SerializeContext.h>
namespace AzToolsFramework
{
namespace Components
{
/**
* Contains Inspector related data that needs to be stored on a per-entity level, such as component ordering per-entity
*/
class EditorInspectorComponent
: public AzToolsFramework::Components::EditorComponentBase
, public EditorInspectorComponentRequestBus::Handler
{
public:
AZ_COMPONENT(EditorInspectorComponent, "{47DE3DDA-50C5-4F50-B1DB-BA4AE66AB056}", EditorComponentBase);
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static bool SerializationConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement);
~EditorInspectorComponent();
////////////////////////////////////////////////////////////////////
// EditorInspectorComponentRequestBus
ComponentOrderArray GetComponentOrderArray() override;
void SetComponentOrderArray(const ComponentOrderArray& componentOrderArray) override;
private:
////////////////////////////////////////////////////////////////////
// AZ::Entity
void Init() override;
////////////////////////////////////////////////////////////////////
/**
* Ensures m_componentOrderEntryArray is up to date before serializing out
*/
void PrepareSave();
/**
* Ensures m_componentOrderArray is up to date after serializing in
*/
void PostLoad();
/**
* ComponentOrderSerializationEvents intercepts the serialization events to ensure the data is complete before and after serialization
*/
class ComponentOrderSerializationEvents
: public AZ::SerializeContext::IEventHandler
{
/**
* Called right before we start reading from the instance pointed by classPtr.
*/
void OnReadBegin(void* classPtr)
{
EditorInspectorComponent* component = reinterpret_cast<EditorInspectorComponent*>(classPtr);
component->PrepareSave();
}
/**
* Called right after we finish writing data to the instance pointed at by classPtr.
*/
void OnWriteEnd(void* classPtr) override
{
EditorInspectorComponent* component = reinterpret_cast<EditorInspectorComponent*>(classPtr);
component->PostLoad();
}
};
/**
* ComponentOrderEntry stores the component id and the sort index (which is the absolute sort index relative to the other entries, 0 is the first, 1 is the second, so on)
* We serialize out the order data in this fashion because the slice data patching system will traditionally use the vector index to know what data goes where
* In the case of this data, it does not make sense to data patch by vector index since the underlying data may have changed and the data patch will create duplicate or incorrect data.
* The slice data patch system has the concept of a "Persistent ID" which can be used instead such that data patches will try to match persistent ids which can be identified regardless
* of vector index. In this way, our vector order no longer matters and the Component Id is now the identifier which the data patcher will use to update the sort index.
*/
struct ComponentOrderEntry
{
AZ_TYPE_INFO(ComponentOrderEntry, "{335C5861-5197-4DD5-A766-EF2B551B0D9D}");
AZ::ComponentId m_componentId;
AZ::u64 m_sortIndex;
};
using ComponentOrderEntryArray = AZStd::vector<ComponentOrderEntry>;
ComponentOrderEntryArray m_componentOrderEntryArray; ///< The serialized order array which uses the persistent id mechanism as described above*/
ComponentOrderArray m_componentOrderArray; ///< The simple vector of component id is what is used by the component order ebus and is generated from the serialized data
bool m_componentOrderIsDirty = true; ///< This flag indicates our stored serialization order data is out of date and must be rebuilt before serialization occurs
};
} // namespace Components
} // namespace AzToolsFramework
@@ -0,0 +1,53 @@
/*
* 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 <AzCore/Component/ComponentBus.h>
#include <AzCore/Component/Component.h>
namespace AzToolsFramework
{
using ComponentOrderArray = AZStd::vector<AZ::ComponentId>;
class EditorInspectorComponentRequests
: public AZ::ComponentBus
{
public:
/**
* Gets the current component sort order array
* @return Container of component ids which is in the proper sorted order of components
*/
virtual ComponentOrderArray GetComponentOrderArray() = 0;
/**
* Sets the current component sort order array
* Emits EditorInspectorComponentNotifications::OnComponentOrderChanged if the new sort order differs from the current ordering.
* @param componentOrderArray Container of component ids which is sorted in the desired sort order of components
*/
virtual void SetComponentOrderArray(const ComponentOrderArray& componentOrderArray) = 0;
};
using EditorInspectorComponentRequestBus = AZ::EBus<EditorInspectorComponentRequests>;
class EditorInspectorComponentNotifications
: public AZ::ComponentBus
{
public:
/**
* Event fired when the order of components in the inspector has been changed
*/
virtual void OnComponentOrderChanged() = 0;
};
using EditorInspectorComponentNotificationBus = AZ::EBus<EditorInspectorComponentNotifications>;
} // namespace AzToolsFramework
@@ -0,0 +1,363 @@
/*
* 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 "EditorComponentBase.h"
#include "EditorLayerComponentBus.h"
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Math/Color.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
class QCryptographicHash;
class QDir;
namespace AzToolsFramework
{
namespace Components
{
class TransformComponent;
}
namespace Layers
{
/// Properties on this class will save to the layer file. Properties on the component
/// will save to the level. Tend toward saving properties here to minimize how often
/// users need to interact with the level file.
class LayerProperties
{
public:
AZ_CLASS_ALLOCATOR(LayerProperties, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(LayerProperties, "{FA61BD6E-769D-4856-BFB5-B535E0FC57B4}");
enum class SaveFormat
{
Xml,
Binary
};
static void Reflect(AZ::ReflectContext* context);
void Clear()
{
m_saveAsBinary = false;
m_color = AZ::Color::CreateOne();
m_isLayerVisible = true;
}
// The color to display the layer in the outliner.
AZ::Color m_color = AZ::Color::CreateOne();
// Default to text files, so the save history is easier to understand in source control.
// This attribute only effects writing layers, and is safe to store here instead of on the component.
// When reading files off disk, Lumberyard figures out the correct format automatically.
bool m_saveAsBinary = false;
// The layer entity needs to be invisible to all other systems, so they don't show up in the viewport.
// Visibility for layers can be toggled in the outliner, though. When layers are made invisible in the outliner,
// it should provide an override to all children, making them invisible.
bool m_isLayerVisible = true;
};
/// Helper class for saving and loading the contents of layers.
class EditorLayer
{
public:
AZ_CLASS_ALLOCATOR(EditorLayer, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(EditorLayer, "{82C661FE-617C-471D-98D5-289570137714}");
static void Reflect(AZ::ReflectContext* context);
EntityList m_layerEntities;
AZ::SliceComponent::SliceAssetToSliceInstancePtrs m_sliceAssetsToSliceInstances;
LayerProperties m_layerProperties;
// Makes it easier to recover a lost layer if the layer's entity ID was known.
AZ::EntityId m_layerEntityId;
};
/// This editor component marks an entity as a layer entity.
/// Layer entities allow the level to be split into multiple files,
/// so content creators can work on the same level at the same time, without conflict.
class EditorLayerComponent
: public AzToolsFramework::Components::EditorComponentBase
, public EditorLayerComponentRequestBus::Handler
, public EditorLayerInfoRequestsBus::Handler
, public AZ::TransformNotificationBus::Handler
{
public:
AZ_EDITOR_COMPONENT(EditorLayerComponent, "{976E05F0-FAC7-43B6-B621-66108AE73FD4}");
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services);
~EditorLayerComponent();
////////////////////////////////////////////////////////////////////
// EditorLayerComponentRequestBus::Handler
LayerResult WriteLayerAndGetEntities(
QString levelAbsoluteFolder,
EntityList& entityList,
AZ::SliceComponent::SliceReferenceToInstancePtrs& layerInstances) override;
void RestoreEditorData() override;
bool HasLayer() override { return true; }
void UpdateLayerNameConflictMapping(AZStd::unordered_map<AZStd::string, int>& nameConflictsMapping) override;
QColor GetLayerColor() override;
AZ::Color GetColorPropertyValue() override;
bool IsSaveFormatBinary() override;
bool IsLayerNameValid() override;
AZ::Outcome<AZStd::string, AZStd::string> GetLayerBaseFileName() override;
AZ::Outcome<AZStd::string, AZStd::string> GetLayerFullFileName() override;
AZ::Outcome<AZStd::string, AZStd::string> GetLayerFullFilePath(const QString& levelAbsoluteFolder) override;
void SetLayerChildrenVisibility(bool visible) override;
bool AreLayerChildrenVisible() override { return m_editableLayerProperties.m_isLayerVisible; }
bool HasUnsavedChanges() override;
void MarkLayerWithUnsavedChanges() override;
void SetOverwriteFlag(bool set) override;
bool GetOverwriteFlag() override { return m_overwriteCheck; }
bool DoesLayerFileExistOnDisk(const QString& levelAbsoluteFolder) override;
bool GatherSaveDependencies(
AZStd::unordered_set<AZ::EntityId>& allLayersToSave,
bool& mustSaveLevel) override;
void AddLayerSaveDependency(const AZ::EntityId& layerSaveDependency) override;
void AddLevelSaveDependency() override;
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// EditorLayerInfoRequestsBus::Handler
void GatherLayerEntitiesWithName(const AZStd::string& layerName, EntityIdSet& layerEntities) override;
////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// AZ::TransformNotificationBus::Handler
// Layers cannot have their parent changed.
void CanParentChange(bool &parentCanChange, AZ::EntityId oldParent, AZ::EntityId newParent) override;
//////////////////////////////////////////////////////////////////////////
// This is not an ebus call because the layer entity is not yet fully setup at the point that entities in the layer are loaded.
LayerResult ReadLayer(
QString levelPakFile,
AZ::SliceComponent::SliceAssetToSliceInstancePtrs& sliceInstances,
AZStd::unordered_map<AZ::EntityId, AZ::Entity*>& uniqueEntities);
// When reading in layers, GetLayerBaseFileName cannot be called because entities aren't yet responding to ebuses.
// The system reading in the layers needs to know the file names to look for them, so used the last saved file name.
AZStd::string GetCachedLayerBaseFileName() { return m_layerFileName; }
// The Layer entities need to be added to the before they are cleaned up.
void CleanupLoadedLayer();
// Sets the layer to the passed in color.
void SetLayerColor(AZ::Color newColor) override { m_editableLayerProperties.m_color = newColor; }
// Sets the save format.
void SetSaveFormat(LayerProperties::SaveFormat saveFormat);
/**
* Creates the right click context menu for layers in the asset browser.
* \param menu The menu to parent this to.
* \param fullFilePath The full file path of the slice.
* \param levelPath The path to the level file.
*/
static void CreateLayerAssetContextMenu(QMenu* menu, const AZStd::string& fullFilePath, QString levelPath);
/**
* Attempts to recover the passed in layer file. This is used when content creators
* accidentally step on each other's toes, and a layer entity gets deleted in a scene.
* \param fullFilePath The full path to the layer to attempt to recover.
*/
static void RecoverLayer(const AZStd::string& fullFilePath);
/**
* Attempts to recover the passed in EditorLayer object. Most call sites should use the RecoverLayer
* that takes in a path to the layer file.
* \param editorLayer The layer object to recover.
* \param newLayerName The name to give the layer entity when it's recovered.
* \param layerParentId The parent for the new layer. Passed in the invalid entity ID for loose layers with no parents.
* \return A success if the layer was recovered, an error if it was not.
*/
static LayerResult RecoverEditorLayer(
const AZStd::shared_ptr<Layers::EditorLayer> editorLayer,
const AZStd::string& newLayerName,
const AZ::EntityId& layerParentId);
// Returns the file extension (without a .) used by the layer system.
static const char* GetLayerExtension() { return "layer"; }
// Returns the file extension (with a .) used by the layer system.
static AZStd::string GetLayerExtensionWithDot() { return AZStd::string::format(".%s", GetLayerExtension()); }
/**
* Creates a layer entity with the given name, and returns the EntityId of the layer entity.
* \param name Name to use for the new layer.
* \param layerColor color of the layer in editor.
* \param saveAsBinary save format for layer, xml or binary.
* \param optionalEntityId optional param to specify entity ID for created layer.
* \return a valid entity ID on successful entity creation
*/
static AZ::EntityId CreateLayerEntity(const AZStd::string& name, const AZ::Color& layerColor, const LayerProperties::SaveFormat& saveAsBinary=LayerProperties::SaveFormat::Xml, const AZ::EntityId& optionalEntityId=AZ::EntityId());
/**
* Helper function for script reflection friendly override.
* Creates a layer entity with the given name, default color
* and xml save format. Returns the EntityId of the layer.
* \param name Name to use for the new layer
* \return a valid entity ID on successful entity creation
*/
static AZ::EntityId CreateLayerEntityFromName(const AZStd::string& name);
// Returns the format the save is currently set to.
AzToolsFramework::Layers::LayerProperties::SaveFormat GetSaveFormat();
protected:
////////////////////////////////////////////////////////////////////
// AZ::Entity
void Init() override;
void Activate() override;
void Deactivate() override;
////////////////////////////////////////////////////////////////////
LayerResult PrepareLayerForSaving(
EditorLayer& layer,
EntityList& entityList,
AZ::SliceComponent::SliceReferenceToInstancePtrs& layerInstances);
LayerResult WriteLayerToStream(
const EditorLayer& layer,
AZ::IO::ByteContainerStream<AZStd::vector<char> >& entitySaveStream);
LayerResult WriteLayerStreamToDisk(
QString levelAbsoluteFolder,
const AZ::IO::ByteContainerStream<AZStd::vector<char> >& entitySaveStream);
LayerResult CreateDirectoryAtPath(const QString& path);
LayerResult PopulateFromLoadedLayerData(
const EditorLayer& loadedLayer,
AZ::SliceComponent::SliceAssetToSliceInstancePtrs& sliceInstances,
AZStd::unordered_map<AZ::EntityId, AZ::Entity*>& uniqueEntities);
void AddUniqueEntitiesAndInstancesFromEditorLayer(
const EditorLayer& loadedLayer,
AZ::SliceComponent::SliceAssetToSliceInstancePtrs& sliceInstances,
AZStd::unordered_map<AZ::EntityId, AZ::Entity*>& uniqueEntities);
QString GetLayerDirectory() const { return "Layers"; }
QString GetLayerTempDirectory() const { return "Layers_Temp"; }
QString GetLayerTempExtension() const { return "layer_temp"; }
// Try writing a temp file a few times, in case the initial temp file isn't writeable for some reason.
int GetMaxTempFileWriteAttempts() const { return 5; }
/**
* Verifies that the passed in layer path is safe to begin a recovery attempt.
* If so, also populates necessary info to recover this layer.
* Also retrieves the name of the layer to use when creating the entity.
* Checks if the ancestry of the layer is available. If not, prompts the user
* if they want it created, or if they want to bail out of the operation.
* \param fullFilePath The full path to the layer file.
* \param newLayerName An output paramater that will be populated with the entity name for this layer.
* \param layerParentId An output parameter that will be populated with the ID of the parent of the layer, if it has one.
*/
static bool CanAttemptToRecoverLayerAndGetLayerInfo(
const AZStd::string& fullFilePath,
AZStd::string& newLayerName,
AZ::EntityId& layerParentId);
/**
* Returns true if the passed in layer is safe to spawn in the scene, false if not.
* This checks for duplicate entity IDs.
* \param loadedLayer The layer to validate.
* \param rootSlice The root slice for the level.
* \return A success if the layer is safe to recover, otherwise an error with a message if not.
*/
static LayerResult IsLayerDataSafeToRecover(const AZStd::shared_ptr<Layers::EditorLayer> loadedLayer, AZ::SliceComponent& rootSlice);
/**
* Creates a layer entity with the given ancestor name.
* This is not parsed for deeper ancestry, if you give this "Grandparent.Parent" and have an entity
* in your scene already named "Grandparent", this won't create "Parent" as a child of "Grandparent".
* \param nearestLayerAncestorName the full ancestor name.
* \return The entity ID fo the missing ancestor.
*/
static AZ::EntityId CreateMissingLayerAncestors(const AZStd::string& nearestLayerAcenstorName);
/**
* Checks if the given entity ID was already discovered. Updates the discovery list with the passed in ID.
* Reports an error if the entity ID was already found. Returns true if it was, false if not.
* This is used when recovering layers, to search for potential entity ID collisions, and cancel the recovery
* if there is a collision.
* \param discoveredIds A list of entity already found.
* \param newEntity The entity to update the list with, and report an error if it was already found.
* \return A success if the entity ID is safe to recover, a failure if not.
*/
static LayerResult UpdateListOfDiscoveredEntityIds(AZStd::unordered_set<AZ::EntityId> &discoveredIds, const AZ::EntityId& newEntity);
// Layer file names generated on each save.
LayerResult GenerateLayerFileName();
LayerResult GetFileHash(QString filePath, QCryptographicHash& hash);
LayerResult GenerateCleanupFailureWarningResult(QString message, const LayerResult* currentFailure);
LayerResult CleanupTempFileAndFolder(QString tempFile, const QDir& layerTempFolder, const LayerResult* currentFailure);
LayerResult CleanupTempFolder(const QDir& layerTempFolder, const LayerResult* currentFailure);
void GatherAllNonLayerNonSliceDescendants(
EntityList& entityList,
EditorLayer& layer,
const AZStd::unordered_map<AZ::EntityId, AZ::Entity*>& entityIdsToEntityPtrs,
AzToolsFramework::Components::TransformComponent& transformComponent) const;
void SetUnsavedChanges(bool unsavedChanges);
// Gets the marker used to include ancestry in layer files created on disk.
// Given a layer hierarchy Grandparent, Parent, and Child, and a separator ".", the separator
// will be used to generate a file named "Grandparent.Parent.Child".
static AZStd::string GetLayerSeparator() { return "."; }
EditorLayer* m_loadedLayer = nullptr;
AZStd::string m_layerFileName;
// Lumberyard's serialization system requires everything in the editor to have a serialized to disk counterpart.
// Layers have their data split into two categories: Stuff that should save to the layer file, and stuff that should
// save to the layer component in the level. To allow the layer component to edit the data that goes in the layer file,
// a placeholder value is serialized. This is only used at edit time, and is copied and cleared during serialization.
LayerProperties m_editableLayerProperties;
LayerProperties m_cachedLayerProperties;
bool m_hasUnsavedChanges = false;
// Users can save individual layers. This can cause problems if an entity is moved between layers
// and only one of those two layers is saved, it will duplicate the entity on the next load.
// This tracks other layers that need to be saved when this layer is saved.
AZStd::unordered_set<AZ::EntityId> m_otherLayersToSave;
// When a new layer is created, mark it as needing to save the level the next time it saves. Existing layers
// will set this flag to false when they load.
bool m_mustSaveLevelWhenLayerSaves = true;
// Setting this flag to true will ask for overwrite confirmation when saving the layer, if a layer with the same name exists on
// disk. If default value isn't false, this will be set to true for all layers when the level is reset(for example, when saving
// a slice), thus prompting a confirmation on further level saves for already loaded layers.
bool m_overwriteCheck = false;
};
}
}
@@ -0,0 +1,211 @@
/*
* 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 <QColor>
#include <QString>
#include <AzCore/Slice/SliceComponent.h>
#include <AzCore/Math/Color.h>
#include "LayerResult.h"
namespace AzToolsFramework
{
namespace Layers
{
/**
* This bus can be used to check if an entity is a layer, and to retrieve information about that layer.
*/
class EditorLayerComponentRequests
: public AZ::ComponentBus
{
public:
/*
* It's expensive to check if an entity has a component, so this ebus call
* is used to check if an entity has a layer.
*/
virtual bool HasLayer() = 0;
/**
* Requests this layer to restore its cached editor data. This information is cached and restored as part of saving,
* so that the data can show up in the inspector to edit the layer, but does not save to the layer entity in the level.
* The data instead saves to the layer file.
*/
virtual void RestoreEditorData() = 0;
/**
* Writes this layer to disk, and gathers entities and instances tracked by this layer, so they can be removed from
* the level slice.
* \param levelAbsoluteFolder The path to the level this layer is saved in.
* \param entityList An output parameter that is populated with entities tracked by this layer.
* \param layerInstances An output parameter that is populated with instances tracked by this layer.
*/
virtual LayerResult WriteLayerAndGetEntities(
QString levelAbsoluteFolder,
AZStd::vector<AZ::Entity*>& entityList,
AZ::SliceComponent::SliceReferenceToInstancePtrs& layerInstances) = 0;
/**
* Populated the passed in map with the number of layers (map value) that have the same name (map key).
* \param nameConflictMapping An output parameter populated with each layer's file name as the key and the number of
* layers with that name as the value.
*/
virtual void UpdateLayerNameConflictMapping(AZStd::unordered_map<AZStd::string, int>& nameConflictMapping) = 0;
/**
* Sets the color of the layer.
*/
virtual void SetLayerColor(AZ::Color newColor) = 0;
/**
* Retrieves the color of the layer.
*/
virtual QColor GetLayerColor() = 0;
/**
* Retrieve the layer's color property value in it's native format
*/
virtual AZ::Color GetColorPropertyValue() = 0;
/**
* Retrieves the save format.
*/
virtual bool IsSaveFormatBinary() = 0;
/**
* Returns true if the layer name is valid for saving to disk.
*/
virtual bool IsLayerNameValid() = 0;
/*
* If successful, returns the layer's file name without an extension. If not successful, returns an error message.
*/
virtual AZ::Outcome<AZStd::string, AZStd::string> GetLayerBaseFileName() = 0;
/**
*If successful, returns the layer's file name with an extension. If not successful, returns an error message.
*/
virtual AZ::Outcome<AZStd::string, AZStd::string> GetLayerFullFileName() = 0;
/**
*If successful, returns the layer's full file path. If not successful, returns an error message.
*/
virtual AZ::Outcome<AZStd::string, AZStd::string> GetLayerFullFilePath(const QString& levelAbsoluteFolder) = 0;
/**
* Returns true if this layer has unsaved changes, false if not.
*/
virtual bool HasUnsavedChanges() = 0;
/**
* Tells the layer to mark itself as having unsaved changes.
*/
virtual void MarkLayerWithUnsavedChanges() = 0;
/**
* Tells the layer to mark itself as needing overwrite check.
* When a new layer is created, mark it as requiring an overwrite check, this will also be set when
* rename is called and reset when the layer is succesfully saved or just loaded
*/
virtual void SetOverwriteFlag(bool set) = 0;
/**
* Returns the value of the overwrite check.
*/
virtual bool GetOverwriteFlag() = 0;
/**
* Returns true if the layer is saved on disk.
*/
virtual bool DoesLayerFileExistOnDisk(const QString& levelAbsoluteFolder) = 0;
/**
* Layers themselves are never visible, and need to be set not visible in other systems to function as designed.
* However, layers still need to be able to toggle on and off a visibility state, so that they can apply an override
* to their children.
* Returns if children of this layer should be visible or not.
*/
virtual bool AreLayerChildrenVisible() = 0;
/**
* Requests the layer to mark its children as visible or not.
* \param visible True to allow children to be visible, false to force children to not be visible.
*/
virtual void SetLayerChildrenVisibility(bool visible) = 0;
/**
* Collects what else must be saved to safely save this layer.
* \param allLayersToSave A set of layer entity IDs that will be saved,
* this is updated with the current layer's dependencies.
* \param mustSaveLevel Set to true if the current level must be saved
* to safely save this layer.
*/
virtual bool GatherSaveDependencies(
AZStd::unordered_set<AZ::EntityId>& allLayersToSave,
bool& mustSaveLevel) = 0;
/**
* Marks the passed in layer Entity ID as a save dependency for this layer.
* This is necessary when an entity switches parents, to make sure that both layers are saved.
* \param layerSaveDependency The layer that must be saved when this layer is saved.
*/
virtual void AddLayerSaveDependency(const AZ::EntityId& layerSaveDependency) = 0;
/**
* Marks the level as a save dependency for this layer.
* This is necessary when an entity switches parents, to make sure that the level is saved with this layer.
*/
virtual void AddLevelSaveDependency() = 0;
};
using EditorLayerComponentRequestBus = AZ::EBus<EditorLayerComponentRequests>;
/**
* This bus is a single bus with multiple listeners. All layers listen in on this bus,
* it's used for checking for layers that share the same file name.
*/
class EditorLayerInfoRequests
: public AZ::EBusTraits
{
public:
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; // multi listener
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; //single bus
/**
* Gathers all layers that have the given layer filename. Used to find duplicate layers.
* \param layerName The name of the layer to search for.
* \param layerEntities An output parameter containing all layers that have the same name.
*/
virtual void GatherLayerEntitiesWithName(const AZStd::string& layerName, AZStd::unordered_set<AZ::EntityId>& layerEntities) = 0;
};
using EditorLayerInfoRequestsBus = AZ::EBus<EditorLayerInfoRequests>;
/**
* This is a single bus with multiple listeners, for allowing systems to listen when specific layer events occur.
*/
class EditorLayerCreationNotification
: public AZ::EBusTraits
{
public:
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; // multi listener
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; //single bus
/**
* Called when a new layer is created. Run custom logic you need for new layers on this bus, including
* adding components to the list of components to add to your layer, if you need custom layer components.
* \param entityId The EntityId of the new layer entity.
* \param componentsToAdd An output list of components to add to the entity. Gathered this way to
* allow all components to be added at once, instead of deactivating and re-activating
* the layer for each listener on this bus adding components.
*/
virtual void OnNewLayerEntity(const AZ::EntityId& entityId, AZStd::vector<AZ::Component*>& componentsToAdd) = 0;
};
using EditorLayerCreationBus = AZ::EBus<EditorLayerCreationNotification>;
}
}
@@ -0,0 +1,83 @@
/*
* 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 "AzToolsFramework_precompiled.h"
#include "EditorLockComponent.h"
#include <AzCore/Serialization/EditContext.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
namespace AzToolsFramework
{
namespace Components
{
void EditorLockComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorLockComponent, EditorComponentBase>()
->Field("Locked", &EditorLockComponent::m_locked)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<EditorLockComponent>("Lock", "Edit-time entity lock state")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide)
->Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::NotPushable)
->Attribute(AZ::Edit::Attributes::HideIcon, true);
}
}
}
void EditorLockComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("EditorLockService", 0x6b15eacf));
}
void EditorLockComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("EditorLockService", 0x6b15eacf));
}
EditorLockComponent::~EditorLockComponent()
{
EditorLockComponentRequestBus::Handler::BusDisconnect();
}
void EditorLockComponent::Init()
{
EditorLockComponentRequestBus::Handler::BusConnect(GetEntityId());
}
void EditorLockComponent::SetLocked(bool locked)
{
if (m_locked != locked)
{
m_locked = locked;
AzToolsFramework::ToolsApplicationRequestBus::Broadcast(
&AzToolsFramework::ToolsApplicationRequestBus::Events::AddDirtyEntity, m_entity->GetId());
// notify individual entities connected to this bus
EditorEntityLockComponentNotificationBus::Event(
m_entity->GetId(), &EditorEntityLockComponentNotifications::OnEntityLockFlagChanged, locked);
}
}
bool EditorLockComponent::GetLocked()
{
return m_locked;
}
} // namespace Components
} // namespace AzToolsFramework
@@ -0,0 +1,45 @@
/*
* 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 "EditorLockComponentBus.h"
#include "EditorComponentBase.h"
namespace AzToolsFramework
{
namespace Components
{
//! Controls whether an Entity is frozen/locked in the Editor.
class EditorLockComponent
: public AzToolsFramework::Components::EditorComponentBase
, public EditorLockComponentRequestBus::Handler
{
public:
AZ_COMPONENT(EditorLockComponent, "{C3A169C9-7EFB-4D6C-8710-3591680D0936}", EditorComponentBase);
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
~EditorLockComponent();
// EditorLockComponentRequestBus ...
void SetLocked(bool locked) override;
bool GetLocked() override;
private:
// AZ::Entity ...
void Init() override;
bool m_locked = false; //!< Whether this entity is individually set to be locked.
};
} // namespace Components
} // namespace AzToolsFramework
@@ -0,0 +1,66 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Component/ComponentBus.h>
#include <AzFramework/Entity/EntityContext.h>
namespace AzToolsFramework
{
/*!
* Controls whether an entity is locked in the editor
* Locked entities can be seen but cannot be selected
*/
class EditorLockComponentRequests
: public AZ::ComponentBus
{
public:
/// Set whether this entity is set to be locked in the editor (individual state/flag).
virtual void SetLocked(bool locked) = 0;
/// Get whether this entity is set to be locked in the editor (individual state/flag).
virtual bool GetLocked() = 0;
};
/// \ref EditorLockRequests
using EditorLockComponentRequestBus = AZ::EBus<EditorLockComponentRequests>;
/**
* Notifications about whether an Entity is locked in the Editor.
* See \ref EditorLockRequests.
*/
class EditorEntityLockComponentNotifications
: public AZ::ComponentBus
{
public:
/// The entity's current internal lock state/flag has changed.
/// ATTN: Only EditorEntityModelEntry listens to this notification.
virtual void OnEntityLockFlagChanged(bool /*locked*/) {}
/// The entity's current lock has changed (in terms of viewport interaction).
/// Note: The event may be caused by a layer lock changing or an individually entity lock changing.
virtual void OnEntityLockChanged(bool /*locked*/) {}
};
/// \ref EditorEntityLockComponentNotifications
using EditorEntityLockComponentNotificationBus = AZ::EBus<EditorEntityLockComponentNotifications>;
/// Alias for EditorEntityLockComponentNotifications - prefer EditorEntityLockComponentNotifications,
/// EditorLockComponentNotifications is deprecated.
using EditorLockComponentNotifications = EditorEntityLockComponentNotifications;
/// Alias for EditorEntityLockComponentNotificationBus - prefer EditorEntityLockComponentNotificationBus,
/// EditorLockComponentNotificationBus is deprecated.
using EditorLockComponentNotificationBus = EditorEntityLockComponentNotificationBus;
} // namespace AzToolsFramework
@@ -0,0 +1,131 @@
/*
* 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 <AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzFramework/Components/NonUniformScaleComponent.h>
namespace AzToolsFramework
{
namespace Components
{
void EditorNonUniformScaleComponent::OnScaleChanged()
{
m_scaleChangedEvent.Signal(m_scale);
}
void EditorNonUniformScaleComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorNonUniformScaleComponent, EditorComponentBase>()
->Version(1)
->Field("NonUniformScale", &EditorNonUniformScaleComponent::m_scale)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
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)
->DataElement(
AZ::Edit::UIHandlers::Default, &EditorNonUniformScaleComponent::m_scale, "Non-uniform Scale",
"Non-uniform scale for this entity only (does not propagate through hierarchy)")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorNonUniformScaleComponent::OnScaleChanged)
;
}
}
}
void EditorNonUniformScaleComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
dependent.push_back(AZ_CRC_CE("TransformService"));
}
void EditorNonUniformScaleComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC_CE("SkyCloudService"));
incompatible.push_back(AZ_CRC_CE("DebugDrawObbService"));
incompatible.push_back(AZ_CRC_CE("DebugDrawService"));
incompatible.push_back(AZ_CRC_CE("EMotionFXActorService"));
incompatible.push_back(AZ_CRC_CE("EMotionFXSimpleMotionService"));
incompatible.push_back(AZ_CRC_CE("GradientTransformService"));
incompatible.push_back(AZ_CRC_CE("LegacyMeshService"));
incompatible.push_back(AZ_CRC_CE("LookAtService"));
incompatible.push_back(AZ_CRC_CE("SequenceService"));
incompatible.push_back(AZ_CRC_CE("ClothMeshService"));
incompatible.push_back(AZ_CRC_CE("PhysXColliderService"));
incompatible.push_back(AZ_CRC_CE("PhysXTriggerService"));
incompatible.push_back(AZ_CRC_CE("PhysXJointService"));
incompatible.push_back(AZ_CRC_CE("PhysXShapeColliderService"));
incompatible.push_back(AZ_CRC_CE("PhysXCharacterControllerService"));
incompatible.push_back(AZ_CRC_CE("PhysXRagdollService"));
incompatible.push_back(AZ_CRC_CE("TouchBendingPhysicsService"));
incompatible.push_back(AZ_CRC_CE("WaterVolumeService"));
incompatible.push_back(AZ_CRC_CE("WhiteBoxService"));
incompatible.push_back(AZ_CRC_CE("NavigationAreaService"));
incompatible.push_back(AZ_CRC_CE("GeometryService"));
incompatible.push_back(AZ_CRC_CE("CapsuleShapeService"));
incompatible.push_back(AZ_CRC_CE("CompoundShapeService"));
incompatible.push_back(AZ_CRC_CE("CylinderShapeService"));
incompatible.push_back(AZ_CRC_CE("DiskShapeService"));
incompatible.push_back(AZ_CRC_CE("FixedVertexContainerService"));
incompatible.push_back(AZ_CRC_CE("PolygonPrismShapeService"));
incompatible.push_back(AZ_CRC_CE("SphereShapeService"));
incompatible.push_back(AZ_CRC_CE("SplineService"));
incompatible.push_back(AZ_CRC_CE("TubeShapeService"));
incompatible.push_back(AZ_CRC_CE("VariableVertexContainerService"));
}
void EditorNonUniformScaleComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC_CE("NonUniformScaleService"));
}
// AZ::Component ...
void EditorNonUniformScaleComponent::Activate()
{
AZ::NonUniformScaleRequestBus::Handler::BusConnect(GetEntityId());
}
void EditorNonUniformScaleComponent::Deactivate()
{
AZ::NonUniformScaleRequestBus::Handler::BusDisconnect();
}
// AZ::NonUniformScaleRequestBus::Handler ...
AZ::Vector3 EditorNonUniformScaleComponent::GetScale() const
{
return m_scale;
}
void EditorNonUniformScaleComponent::SetScale(const AZ::Vector3& scale)
{
m_scale = scale;
}
void EditorNonUniformScaleComponent::RegisterScaleChangedEvent(AZ::NonUniformScaleChangedEvent::Handler& handler)
{
handler.Connect(m_scaleChangedEvent);
}
// EditorComponentBase ...
void EditorNonUniformScaleComponent::BuildGameEntity(AZ::Entity* gameEntity)
{
auto nonUniformScaleComponent = gameEntity->CreateComponent<AzFramework::NonUniformScaleComponent>();
nonUniformScaleComponent->SetScale(m_scale);
}
} // namespace Components
} // namespace AzToolsFramework
@@ -0,0 +1,57 @@
/*
* 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 <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
#include <AzCore/Component/NonUniformScaleBus.h>
namespace AzToolsFramework
{
namespace Components
{
//! Allows working with non-uniform scale in the editor.
class EditorNonUniformScaleComponent
: public AzToolsFramework::Components::EditorComponentBase
, public AZ::NonUniformScaleRequestBus::Handler
{
public:
AZ_EDITOR_COMPONENT(EditorNonUniformScaleComponent, "{2933FB4F-B3DA-4CD1-8106-F37300730777}", EditorComponentBase);
static void Reflect(AZ::ReflectContext* context);
EditorNonUniformScaleComponent() = default;
~EditorNonUniformScaleComponent() = default;
// AZ::Component ...
void Activate() override;
void Deactivate() override;
// AZ::NonUniformScaleRequestBus::Handler ...
AZ::Vector3 GetScale() const override;
void SetScale(const AZ::Vector3& scale) override;
void RegisterScaleChangedEvent(AZ::NonUniformScaleChangedEvent::Handler& handler);
private:
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
void OnScaleChanged();
// EditorComponentBase ...
void BuildGameEntity(AZ::Entity* gameEntity) override;
AZ::Vector3 m_scale = AZ::Vector3::CreateOne();
AZ::NonUniformScaleChangedEvent m_scaleChangedEvent;
};
} // namespace Components
} // namespace AzToolsFramework
@@ -0,0 +1,107 @@
/*
* 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 "AzToolsFramework_precompiled.h"
#include <AzToolsFramework/ToolsComponents/EditorOnlyEntityComponent.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
namespace AzToolsFramework
{
namespace Components
{
void EditorOnlyEntityComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorOnlyEntityComponent, EditorComponentBase>()
->Field("IsEditorOnly", &EditorOnlyEntityComponent::m_isEditorOnly)
;
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<EditorOnlyEntityComponent>("Editor-Only Flag Handler", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide)
->Attribute(AZ::Edit::Attributes::HideIcon, true)
->DataElement(AZ::Edit::UIHandlers::Default, &EditorOnlyEntityComponent::m_isEditorOnly,
"Editor Only",
"Marks the entity for editor-use only. If true, the entity will not be exported for use in runtime contexts (including dynamic slices).")
;
}
}
}
void EditorOnlyEntityComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("EditorOnlyEntityService", 0x7010c39d));
}
void EditorOnlyEntityComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("EditorOnlyEntityService", 0x7010c39d));
}
EditorOnlyEntityComponent::EditorOnlyEntityComponent()
: m_isEditorOnly(false)
{
}
EditorOnlyEntityComponent::~EditorOnlyEntityComponent()
{
}
void EditorOnlyEntityComponent::Init()
{
EditorComponentBase::Init();
// Connect at Init()-time to allow slice compilation to query for editor only status.
EditorOnlyEntityComponentRequestBus::Handler::BusConnect(GetEntityId());
}
void EditorOnlyEntityComponent::Activate()
{
EditorComponentBase::Activate();
EditorOnlyEntityComponentRequestBus::Handler::BusConnect(GetEntityId());
}
void EditorOnlyEntityComponent::Deactivate()
{
EditorOnlyEntityComponentRequestBus::Handler::BusDisconnect();
EditorComponentBase::Deactivate();
}
bool EditorOnlyEntityComponent::IsEditorOnlyEntity()
{
return m_isEditorOnly;
}
void EditorOnlyEntityComponent::SetIsEditorOnlyEntity(bool isEditorOnly)
{
if (isEditorOnly != m_isEditorOnly)
{
AzToolsFramework::ScopedUndoBatch undo("Set IsEditorOnly");
m_isEditorOnly = isEditorOnly;
EditorOnlyEntityComponentNotificationBus::Broadcast(&EditorOnlyEntityComponentNotificationBus::Events::OnEditorOnlyChanged, GetEntityId(), m_isEditorOnly);
undo.MarkEntityDirty(GetEntityId());
}
}
} // namespace Components
} // namespace AzToolsFramework
@@ -0,0 +1,59 @@
/*
* 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 <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
#include <AzToolsFramework/ToolsComponents/EditorOnlyEntityComponentBus.h>
#pragma once
namespace AzToolsFramework
{
namespace Components
{
/**
* Acts as storage for the "editor-only" flag on entities, and offers an API for getting/setting the value.
*/
class EditorOnlyEntityComponent
: public AzToolsFramework::Components::EditorComponentBase
, public EditorOnlyEntityComponentRequestBus::Handler
{
public:
AZ_EDITOR_COMPONENT(EditorOnlyEntityComponent, "{22A16F1D-6D49-422D-AAE9-91AE45B5D3E7}");
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
////////////////////////////////////////////////////////////////////
// EditorOnlyEntityComponentRequestBus
bool IsEditorOnlyEntity() override;
void SetIsEditorOnlyEntity(bool isEditorOnly) override;
////////////////////////////////////////////////////////////////////
EditorOnlyEntityComponent();
~EditorOnlyEntityComponent() override;
private:
////////////////////////////////////////////////////////////////////
// AZ::Entity
void Init() override;
void Activate() override;
void Deactivate() override;
////////////////////////////////////////////////////////////////////
bool m_isEditorOnly; ///< Is the entity marked as editor-only?
};
} // namespace Components
} // namespace AzToolsFramework
@@ -0,0 +1,43 @@
/*
* 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 <AzCore/EBus/EBus.h>
#pragma once
namespace AzToolsFramework
{
class EditorOnlyEntityComponentRequests
: public AZ::ComponentBus
{
public:
virtual bool IsEditorOnlyEntity() = 0;
virtual void SetIsEditorOnlyEntity(bool isEditorOnly) = 0;
};
using EditorOnlyEntityComponentRequestBus = AZ::EBus<EditorOnlyEntityComponentRequests>;
/**
* This bus will notify handlers when an entity's "editor only" flag has changed
*/
class EditorOnlyEntityComponentNotifications
: public AZ::EBusTraits
{
public:
virtual~EditorOnlyEntityComponentNotifications() = default;
virtual void OnEditorOnlyChanged(AZ::EntityId entityId, bool isEditorOnly) = 0;
};
using EditorOnlyEntityComponentNotificationBus = AZ::EBus<EditorOnlyEntityComponentNotifications>;
} // namespace AzToolsFramework
@@ -0,0 +1,11 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or
* a third party where indicated.
*
* 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.
*
*/
@@ -0,0 +1,29 @@
/*
* 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 <AzCore/Component/ComponentBus.h>
#include <AzCore/Component/Component.h>
namespace AzToolsFramework
{
class EditorPendingCompositionRequests
: public AZ::ComponentBus
{
public:
virtual void GetPendingComponents(AZStd::vector<AZ::Component*>& components) = 0;
virtual void AddPendingComponent(AZ::Component* componentToAdd) = 0;
virtual void RemovePendingComponent(AZ::Component* componentToRemove) = 0;
};
using EditorPendingCompositionRequestBus = AZ::EBus<EditorPendingCompositionRequests>;
} // namespace AzToolsFramework
@@ -0,0 +1,128 @@
/*
* 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 "AzToolsFramework_precompiled.h"
#include "EditorPendingCompositionComponent.h"
#include <AzCore/Serialization/EditContext.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
namespace AzToolsFramework
{
namespace Components
{
void EditorPendingCompositionComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorPendingCompositionComponent, EditorComponentBase>()
->Field("PendingComponents", &EditorPendingCompositionComponent::m_pendingComponents)
;
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<EditorPendingCompositionComponent>("Pending Components", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide)
->Attribute(AZ::Edit::Attributes::HideIcon, true)
->Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::HideOnAdd | AZ::Edit::SliceFlags::PushWhenHidden)
;
}
}
}
void EditorPendingCompositionComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("EditorPendingCompositionService", 0x6b5b794f));
}
void EditorPendingCompositionComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("EditorPendingCompositionService", 0x6b5b794f));
}
void EditorPendingCompositionComponent::GetPendingComponents(AZStd::vector<AZ::Component*>& components)
{
components.insert(components.end(), m_pendingComponents.begin(), m_pendingComponents.end());
}
void EditorPendingCompositionComponent::AddPendingComponent(AZ::Component* componentToAdd)
{
AZ_Assert(componentToAdd, "Unable to add a pending component that is nullptr");
if (componentToAdd && AZStd::find(m_pendingComponents.begin(), m_pendingComponents.end(), componentToAdd) == m_pendingComponents.end())
{
m_pendingComponents.push_back(componentToAdd);
bool isDuringUndo = false;
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(isDuringUndo, &AzToolsFramework::ToolsApplicationRequestBus::Events::IsDuringUndoRedo);
if (isDuringUndo)
{
SetDirty();
}
}
}
void EditorPendingCompositionComponent::RemovePendingComponent(AZ::Component* componentToRemove)
{
AZ_Assert(componentToRemove, "Unable to remove a pending component that is nullptr");
if (componentToRemove)
{
m_pendingComponents.erase(AZStd::remove(m_pendingComponents.begin(), m_pendingComponents.end(), componentToRemove), m_pendingComponents.end());
bool isDuringUndo = false;
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(isDuringUndo, &AzToolsFramework::ToolsApplicationRequestBus::Events::IsDuringUndoRedo);
if (isDuringUndo)
{
SetDirty();
}
}
};
EditorPendingCompositionComponent::~EditorPendingCompositionComponent()
{
for (auto pendingComponent : m_pendingComponents)
{
delete pendingComponent;
}
m_pendingComponents.clear();
// We disconnect from the bus here because we need to be able to respond even if the entity and component are not active
// This is a special case for certain EditorComponents only!
EditorPendingCompositionRequestBus::Handler::BusDisconnect();
}
void EditorPendingCompositionComponent::Init()
{
EditorComponentBase::Init();
// We connect to the bus here because we need to be able to respond even if the entity and component are not active
// This is a special case for certain EditorComponents only!
EditorPendingCompositionRequestBus::Handler::BusConnect(GetEntityId());
// Set the entity* for each pending component
for (auto pendingComponent : m_pendingComponents)
{
auto editorComponentBaseComponent = azrtti_cast<Components::EditorComponentBase*>(pendingComponent);
AZ_Assert(editorComponentBaseComponent, "Editor component does not derive from EditorComponentBase");
editorComponentBaseComponent->SetEntity(GetEntity());
}
}
void EditorPendingCompositionComponent::Activate()
{
EditorComponentBase::Activate();
}
void EditorPendingCompositionComponent::Deactivate()
{
EditorComponentBase::Deactivate();
}
} // namespace Components
} // namespace AzToolsFramework
@@ -0,0 +1,52 @@
/*
* 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 "EditorComponentBase.h"
#include "EditorPendingCompositionBus.h"
namespace AzToolsFramework
{
namespace Components
{
/**
* Contains pending components to be added to the entity we are attached to.
*/
class EditorPendingCompositionComponent
: public AzToolsFramework::Components::EditorComponentBase
, public EditorPendingCompositionRequestBus::Handler
{
public:
AZ_COMPONENT(EditorPendingCompositionComponent, "{D40FCB35-153D-45B3-AF6D-7BA576D8AFBB}", EditorComponentBase);
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
////////////////////////////////////////////////////////////////////
// EditorPendingCompositionRequestBus
void GetPendingComponents(AZStd::vector<AZ::Component*>& components) override;
void AddPendingComponent(AZ::Component* componentToAdd) override;
void RemovePendingComponent(AZ::Component* componentToRemove) override;
////////////////////////////////////////////////////////////////////
~EditorPendingCompositionComponent() override;
private:
////////////////////////////////////////////////////////////////////
// AZ::Entity
void Init() override;
void Activate() override;
void Deactivate() override;
////////////////////////////////////////////////////////////////////
AZStd::vector<AZ::Component*> m_pendingComponents;
};
} // namespace Components
} // namespace AzToolsFramework
@@ -0,0 +1,149 @@
/*
* 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 "AzToolsFramework_precompiled.h"
#include "EditorSelectionAccentSystemComponent.h"
#include <AzCore/Debug/Profiler.h>
#include <AzCore/Debug/Trace.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Component/TransformBus.h>
#include <AzToolsFramework/API/ComponentEntityObjectBus.h>
#include <AzFramework/Entity/EntityContextBus.h>
#include <AzCore/Slice/SliceComponent.h>
namespace AzToolsFramework
{
namespace Components
{
void EditorSelectionAccentSystemComponent::Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
{
serialize->Class<EditorSelectionAccentSystemComponent, AZ::Component>()
->Version(0)
;
if (AZ::EditContext* ec = serialize->GetEditContext())
{
ec->Class<EditorSelectionAccentSystemComponent>("EditorSelectionAccenting", "Used for selection accenting behavior in the viewport")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System"))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
;
}
}
}
void EditorSelectionAccentSystemComponent::Activate()
{
AzToolsFramework::ToolsApplicationEvents::Bus::Handler::BusConnect();
AzToolsFramework::Components::EditorSelectionAccentingRequestBus::Handler::BusConnect();
}
void EditorSelectionAccentSystemComponent::AfterEntityHighlightingChanged()
{
if (!m_isAccentRefreshQueued)
{
QueueAccentRefresh();
}
}
void EditorSelectionAccentSystemComponent::AfterEntitySelectionChanged(const AzToolsFramework::EntityIdList&, const AzToolsFramework::EntityIdList&)
{
if (!m_isAccentRefreshQueued)
{
QueueAccentRefresh();
}
}
void EditorSelectionAccentSystemComponent::QueueAccentRefresh()
{
AZ_Assert(!m_isAccentRefreshQueued, "Queueing another accent refresh when one is already queued!");
m_isAccentRefreshQueued = true;
AZStd::function<void()> accentRefreshCallback =
[this]()
{
AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::AzToolsFramework, "EditorSelectionAccentSystemComponent::QueueAccentRefresh:AccentRefreshCallback");
InvalidateAccents();
RecalculateAndApplyAccents();
m_isAccentRefreshQueued = false;
};
AZ::TickBus::QueueFunction(accentRefreshCallback);
}
void EditorSelectionAccentSystemComponent::ForceSelectionAccentRefresh()
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
InvalidateAccents();
RecalculateAndApplyAccents();
}
void EditorSelectionAccentSystemComponent::InvalidateAccents()
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
for (const AZ::EntityId& accentedEntity : m_currentlyAccentedEntities)
{
AzToolsFramework::ComponentEntityEditorRequestBus::Event(accentedEntity, &AzToolsFramework::ComponentEntityEditorRequests::SetSandboxObjectAccent, ComponentEntityAccentType::None);
}
m_currentlyAccentedEntities.clear();
}
void EditorSelectionAccentSystemComponent::RecalculateAndApplyAccents()
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
AzToolsFramework::EntityIdList selectedEntities;
AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult(selectedEntities, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities);
AzToolsFramework::EntityIdSet selectedEntitiesSet;
selectedEntitiesSet.insert(selectedEntities.begin(), selectedEntities.end());
for (const AZ::EntityId& selectedEntity : selectedEntities)
{
// Set selected entities accent to 'Selected'
AzToolsFramework::ComponentEntityEditorRequestBus::Event(selectedEntity, &AzToolsFramework::ComponentEntityEditorRequests::SetSandboxObjectAccent, ComponentEntityAccentType::Selected);
m_currentlyAccentedEntities.insert(selectedEntity);
// Find all selected entities children and Set their accent to 'Parent Selected'
AzToolsFramework::EntityIdList descendants;
AZ::TransformBus::EventResult(descendants, selectedEntity, &AZ::TransformInterface::GetAllDescendants);
for (const AZ::EntityId& descendant : descendants)
{
if (selectedEntitiesSet.find(descendant) == selectedEntitiesSet.end())
{
AzToolsFramework::ComponentEntityEditorRequestBus::Event(descendant, &ComponentEntityEditorRequests::SetSandboxObjectAccent, ComponentEntityAccentType::ParentSelected);
m_currentlyAccentedEntities.insert(descendant);
}
}
}
// Find Hovered entities
// Set their accent to 'Hover'
AzToolsFramework::EntityIdList highlightedEntities;
AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult(highlightedEntities, &AzToolsFramework::ToolsApplicationRequests::GetHighlightedEntities);
for (const AZ::EntityId& highlightedEntity : highlightedEntities)
{
AzToolsFramework::ComponentEntityEditorRequestBus::Event(highlightedEntity, &ComponentEntityEditorRequests::SetSandboxObjectAccent, ComponentEntityAccentType::Hover);
m_currentlyAccentedEntities.insert(highlightedEntity);
}
}
void EditorSelectionAccentSystemComponent::Deactivate()
{
AzToolsFramework::ToolsApplicationEvents::Bus::Handler::BusConnect();
AzToolsFramework::Components::EditorSelectionAccentingRequestBus::Handler::BusDisconnect();
}
}
} // namespace LmbrCentral
@@ -0,0 +1,93 @@
/*
* 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 <AzCore/Component/Component.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include "EditorSelectionAccentingBus.h"
namespace AzToolsFramework
{
namespace Components
{
class EditorSelectionAccentSystemComponent
: public AZ::Component
, public AzToolsFramework::ToolsApplicationEvents::Bus::Handler
, public AzToolsFramework::Components::EditorSelectionAccentingRequestBus::Handler
{
public:
enum class ComponentEntityAccentType : AZ::u8
{
None,
Hover,
Selected,
ParentSelected,
SliceSelected
};
AZ_COMPONENT(EditorSelectionAccentSystemComponent, "{6E0F0E2C-1FE5-4AFB-9672-DC92B3D2D844}");
~EditorSelectionAccentSystemComponent() override = default;
static void Reflect(AZ::ReflectContext* context);
////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
void Activate() override;
void Deactivate() override;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
void BeforeEntitySelectionChanged() override {};
void AfterEntitySelectionChanged(const AzToolsFramework::EntityIdList&, const AzToolsFramework::EntityIdList&) override;
void BeforeEntityHighlightingChanged() override {};
void AfterEntityHighlightingChanged() override;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
void ForceSelectionAccentRefresh() override;
////////////////////////////////////////////////////////////////////////
protected:
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("EditorSelectionAccentingSelectionService", 0x8b5253cf));
}
/**
* \brief Queues the invalidation, recalculation and application of accents
*/
void QueueAccentRefresh();
/**
* \brief Invalidates all currently applied accents
*/
void InvalidateAccents();
/**
* \brief Recalculates and applies accenting on the currently selected set of entities
*/
void RecalculateAndApplyAccents();
// Stores a list of entities that are currently accented
AZStd::unordered_set<AZ::EntityId> m_currentlyAccentedEntities;
// Indicates if a refresh of accenting is already queued
bool m_isAccentRefreshQueued = false;
};
}
using EntityAccentType = Components::EditorSelectionAccentSystemComponent::ComponentEntityAccentType;
} // namespace LmbrCentral
@@ -0,0 +1,43 @@
/*
* 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 <AzCore/EBus/EBus.h>
namespace AzToolsFramework
{
namespace Components
{
//////////////////////////////////////////////////////////////////////////
// Applies selection accents to all selected entities
//////////////////////////////////////////////////////////////////////////
class EditorSelectionAccentingRequests
: public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// Bus configuration
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
/**
* \brief Invalidates then Recalculates and Applies accenting on the currently selected set of entities
* This shouldn't be necessary to call except in unique circumstances, as it is automatically done
* on highlight and selection changes.
*/
virtual void ForceSelectionAccentRefresh() = 0;
};
using EditorSelectionAccentingRequestBus = AZ::EBus<EditorSelectionAccentingRequests>;
} // namespace Components
} // namespace AzToolsFramework
@@ -0,0 +1,75 @@
/*
* 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 <AzCore/Component/ComponentBus.h>
#include <AzCore/std/parallel/mutex.h>
#include <AzFramework/Entity/EntityContext.h>
namespace AzToolsFramework
{
/**
* Controls whether an Entity is shown or hidden in the Editor
* The "Visibility Flag" controls whether an entity can ever be shown.
* "Current Visibility" is the entity's current state, a combination
* of factors (including the visibility flag) contribute to this.
* \note "Visibility" here refers to the ability to be shown,
* it does refer to whether the entity is currently on camera.
* \note This functionality is editor-only, it is not available in-game.
*/
class EditorVisibilityRequests
: public AZ::ComponentBus
{
public:
using MutexType = AZStd::recursive_mutex;
/// Set whether this entity is set to be visible in the editor (individual state/flag).
virtual void SetVisibilityFlag(bool flag) = 0;
/// Get whether this entity is set to be visible in the editor (individual state/flag).
virtual bool GetVisibilityFlag() = 0;
};
/// \ref EditorVisibilityRequests
using EditorVisibilityRequestBus = AZ::EBus<EditorVisibilityRequests>;
/**
* Messages about whether an Entity is shown or hidden in the Editor.
* See \ref EditorVisibilityRequests.
*/
class EditorEntityVisibilityNotifications
: public AZ::ComponentBus
{
public:
/// The entity's current visibility has changed.
/// \note This does not reflect whether the entity is currently on-camera.
virtual void OnEntityVisibilityChanged(bool /*visibility*/) {}
/// The entity's visibility flag has been changed.
/// Even if the flag is set true, the entity may be hidden for other reasons.
/// ATTN: Only EditorEntityModelEntry should listen to this notification.
virtual void OnEntityVisibilityFlagChanged(bool /*flag*/) {}
};
/// \ref EditorEntityVisibilityNotifications
using EditorEntityVisibilityNotificationBus = AZ::EBus<EditorEntityVisibilityNotifications>;
/// Alias for EditorEntityVisibilityNotifications - prefer EditorEntityVisibilityNotifications,
/// EditorVisibilityNotifications is deprecated.
using EditorVisibilityNotifications = EditorEntityVisibilityNotifications;
/// Alias for EditorEntityVisibilityNotificationBus - prefer EditorEntityVisibilityNotificationBus,
/// EditorVisibilityNotificationBus is deprecated.
using EditorVisibilityNotificationBus = EditorEntityVisibilityNotificationBus;
} // namespace AzToolsFramework
@@ -0,0 +1,87 @@
/*
* 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 "AzToolsFramework_precompiled.h"
#include "EditorVisibilityComponent.h"
#include <AzCore/Serialization/EditContext.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
namespace AzToolsFramework
{
namespace Components
{
void EditorVisibilityComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorVisibilityComponent, EditorComponentBase>()
->Field("VisibilityFlag", &EditorVisibilityComponent::m_visibilityFlag)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<EditorVisibilityComponent>("Visibility", "Edit-time entity visibility")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide)
->Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::NotPushable)
->Attribute(AZ::Edit::Attributes::HideIcon, true);
}
}
}
void EditorVisibilityComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("EditorVisibilityService", 0x90888caf));
}
void EditorVisibilityComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("EditorVisibilityService", 0x90888caf));
}
EditorVisibilityComponent::~EditorVisibilityComponent()
{
// We disconnect from the bus here because we need to be able to respond even if the entity and component are not active
// This is a special case for certain EditorComponents only!
EditorVisibilityRequestBus::Handler::BusDisconnect();
}
void EditorVisibilityComponent::Init()
{
// We connect to the bus here because we need to be able to respond even if the entity and component are not active
// This is a special case for certain EditorComponents only!
EditorVisibilityRequestBus::Handler::BusConnect(GetEntityId());
}
void EditorVisibilityComponent::SetVisibilityFlag(bool flag)
{
if (m_visibilityFlag != flag)
{
m_visibilityFlag = flag;
AzToolsFramework::ToolsApplicationRequestBus::Broadcast(
&AzToolsFramework::ToolsApplicationRequestBus::Events::AddDirtyEntity, m_entity->GetId());
// notify individual entities connected to this bus
EditorEntityVisibilityNotificationBus::Event(
m_entity->GetId(), &EditorEntityVisibilityNotifications::OnEntityVisibilityFlagChanged, flag);
}
}
bool EditorVisibilityComponent::GetVisibilityFlag()
{
return m_visibilityFlag;
}
} // namespace Components
} // namespace AzToolsFramework
@@ -0,0 +1,45 @@
/*
* 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 "EditorVisibilityBus.h"
#include "EditorComponentBase.h"
namespace AzToolsFramework
{
namespace Components
{
//! Controls whether an Entity is shown or hidden in the Editor.
class EditorVisibilityComponent
: public AzToolsFramework::Components::EditorComponentBase
, public EditorVisibilityRequestBus::Handler
{
public:
AZ_COMPONENT(EditorVisibilityComponent, "{88E08E78-5C2F-4943-9F73-C115E6FFAB43}", EditorComponentBase);
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
~EditorVisibilityComponent();
// EditorVisibilityRequestBus ...
void SetVisibilityFlag(bool flag) override;
bool GetVisibilityFlag() override;
private:
// AZ::Entity ...
void Init() override;
bool m_visibilityFlag = true; //!< Whether this entity is individually set to be shown.
};
} // namespace Components
} // namespace AzToolsFramework
@@ -0,0 +1,378 @@
/*
* 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 "AzToolsFramework_precompiled.h"
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Component/ComponentExport.h>
#include <AzCore/Slice/SliceComponent.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzFramework/Components/EditorEntityEvents.h>
#include <AzToolsFramework/ToolsComponents/GenericComponentWrapper.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
namespace AzToolsFramework
{
namespace Components
{
/**
* Custom export callback for GenericComponentWrapper, invoked by the slice compiler.
* The Wrapper component simply exports the inner template, which is the runtime/non-editor component.
*/
AZ::ExportedComponent ExportTemplateComponent(AZ::Component* thisComponent, const AZ::PlatformTagSet& /*platformTags*/)
{
GenericComponentWrapper* wrapper = static_cast<GenericComponentWrapper*>(thisComponent);
return AZ::ExportedComponent(wrapper->GetTemplate(), false);
}
////////////////////////////////////////////////////////////////////////
// GenericComponentWrapper
////////////////////////////////////////////////////////////////////////
void GenericComponentWrapper::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<GenericComponentWrapper, EditorComponentBase>()
->Field("m_template", &GenericComponentWrapper::m_template);
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<GenericComponentWrapper>("GenericComponentWrapper", "This should be hidden!")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &GenericComponentWrapper::GetDisplayName)
->Attribute(AZ::Edit::Attributes::DescriptionTextOverride, &GenericComponentWrapper::GetDisplayDescription)
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::RuntimeExportCallback, &ExportTemplateComponent)
->DataElement("", &GenericComponentWrapper::m_template, "m_template", "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ_CRC("PropertyVisibility_ShowChildrenOnly", 0xef428f20));
}
}
}
GenericComponentWrapper::GenericComponentWrapper()
{
}
GenericComponentWrapper::GenericComponentWrapper(const AZ::SerializeContext::ClassData* templateClassData)
{
EBUS_EVENT_ID_RESULT(m_template, templateClassData->m_typeId, AZ::ComponentDescriptorBus, CreateComponent);
}
GenericComponentWrapper::GenericComponentWrapper(AZ::Component* templateClassInstance)
{
if (templateClassInstance)
{
if (templateClassInstance->GetEntity())
{
AZ_Error("GenericComponentWrapper", false, "Component must be detached from entity before placing inside GenericComponentWrapper.");
}
else
{
m_id = templateClassInstance->GetId();
m_template = templateClassInstance;
}
}
}
GenericComponentWrapper::~GenericComponentWrapper()
{
if (m_template)
{
delete m_template;
}
}
GenericComponentWrapper::GenericComponentWrapper(const GenericComponentWrapper& RHS)
: m_displayName(RHS.m_displayName)
, m_displayDescription(RHS.m_displayDescription)
{
if (GetEntity())
{
AZ_Assert(GetEntity()->GetState() <= AZ::Entity::State::Init, "Entity should not be activated when copying components");
}
AZ::SerializeContext* context = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
m_template = context->CloneObject<AZ::Component>(RHS.m_template);
m_templateEvents = azrtti_cast<AzFramework::EditorEntityEvents*>(m_template);
}
GenericComponentWrapper::GenericComponentWrapper(GenericComponentWrapper&& RHS)
: m_displayName(AZStd::move(RHS.m_displayName))
, m_displayDescription(AZStd::move(RHS.m_displayDescription))
{
if (GetEntity())
{
AZ_Assert(GetEntity()->GetState() <= AZ::Entity::State::Init, "Entity should not be activated when copying components");
}
m_template = AZStd::move(RHS.m_template);
RHS.m_template = nullptr;
m_templateEvents = azrtti_cast<AzFramework::EditorEntityEvents*>(m_template);
}
GenericComponentWrapper& GenericComponentWrapper::operator=(const GenericComponentWrapper& RHS)
{
if (GetEntity())
{
AZ_Assert(GetEntity()->GetState() <= AZ::Entity::State::Init, "Entity should not be activated when copying components");
}
AZ::SerializeContext* context = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
m_template = context->CloneObject<AZ::Component>(RHS.m_template);
m_templateEvents = azrtti_cast<AzFramework::EditorEntityEvents*>(m_template);
m_displayName = RHS.m_displayName;
m_displayDescription = RHS.m_displayDescription;
return *this;
}
GenericComponentWrapper& GenericComponentWrapper::operator=(GenericComponentWrapper&& RHS)
{
if (GetEntity())
{
AZ_Assert(GetEntity()->GetState() <= AZ::Entity::State::Init, "Entity should not be activated when copying components");
}
m_template = AZStd::move(RHS.m_template);
RHS.m_template = nullptr;
m_templateEvents = azrtti_cast<AzFramework::EditorEntityEvents*>(m_template);
m_displayName = AZStd::move(RHS.m_displayName);
m_displayDescription = AZStd::move(RHS.m_displayDescription);
return *this;
}
const char* GenericComponentWrapper::GetDisplayName()
{
if (m_displayName.empty())
{
if (m_template)
{
m_displayName = GetFriendlyComponentName(m_template);
}
}
return m_displayName.c_str();
}
const char* GenericComponentWrapper::GetDisplayDescription()
{
if (m_displayDescription.empty())
{
if (m_template)
{
m_displayDescription = GetFriendlyComponentDescription(m_template);
}
}
return m_displayDescription.c_str();
}
void GenericComponentWrapper::Init()
{
EditorComponentBase::Init();
if (m_template)
{
m_displayName = GetFriendlyComponentName(m_template);
m_displayDescription = GetFriendlyComponentDescription(m_template);
if (m_displayDescription.empty())
{
m_displayDescription = m_displayName;
}
m_templateEvents = azrtti_cast<AzFramework::EditorEntityEvents*>(m_template);
if (m_templateEvents)
{
m_templateEvents->EditorInit(GetEntityId());
}
}
}
void GenericComponentWrapper::Activate()
{
EditorComponentBase::Activate();
if (m_templateEvents)
{
m_templateEvents->EditorActivate(GetEntityId());
AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(GetEntityId());
}
}
void GenericComponentWrapper::Deactivate()
{
EditorComponentBase::Deactivate();
if (m_templateEvents)
{
AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect();
m_templateEvents->EditorDeactivate(GetEntityId());
}
}
const AZ::TypeId& GenericComponentWrapper::GetUnderlyingComponentType() const
{
if (m_template)
{
return m_template->RTTI_GetType();
}
return RTTI_GetType();
}
void GenericComponentWrapper::BuildGameEntity(AZ::Entity* gameEntity)
{
if (m_template)
{
AZ::SerializeContext* context = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
if (!context)
{
AZ_Error("GenericComponentWrapper", false, "Can't get serialize context from component application.");
return;
}
gameEntity->AddComponent(context->CloneObject(m_template));
}
}
AZ::ComponentValidationResult GenericComponentWrapper::ValidateComponentRequirements(
const AZ::ImmutableEntityVector& sliceEntities, const AZStd::unordered_set<AZ::Crc32>& platformTags) const
{
AZ::ComponentValidationResult baseClassResult = EditorComponentBase::ValidateComponentRequirements(sliceEntities, platformTags);
if (!baseClassResult.IsSuccess())
{
return baseClassResult;
}
if (m_template)
{
return m_template->ValidateComponentRequirements(sliceEntities, platformTags);
}
return AZ::Success();
}
void GenericComponentWrapper::DisplayEntityViewport(
const AzFramework::ViewportInfo& /*viewportInfo*/,
AzFramework::DebugDisplayRequests& debugDisplay)
{
if (m_templateEvents)
{
m_templateEvents->EditorDisplay(GetEntityId(), debugDisplay, GetWorldTM());
}
}
void GenericComponentWrapper::SetPrimaryAsset(const AZ::Data::AssetId& assetId)
{
if (m_templateEvents)
{
m_templateEvents->EditorSetPrimaryAsset(assetId);
}
}
AZ::Component* GenericComponentWrapper::ReleaseTemplate()
{
AZ::Component* component = m_template;
m_template = nullptr;
return component;
}
class GenericComponentWrapperDescriptor
: public AZ::ComponentDescriptorHelper<GenericComponentWrapper>
{
public:
AZ_CLASS_ALLOCATOR(GenericComponentWrapperDescriptor, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(GenericComponentWrapperDescriptor, "{3326B218-282B-4985-AEDE-39A77D48AD57}");
AZ::ComponentDescriptor* GetTemplateDescriptor(const AZ::Component* instance) const
{
AZ::ComponentDescriptor* templateDescriptor = nullptr;
const GenericComponentWrapper* wrapper = azrtti_cast<const GenericComponentWrapper*>(instance);
if (wrapper && wrapper->GetTemplate())
{
EBUS_EVENT_ID_RESULT(
templateDescriptor, wrapper->GetTemplate()->RTTI_GetType(),
AZ::ComponentDescriptorBus, GetDescriptor);
}
return templateDescriptor;
}
void Reflect(AZ::ReflectContext* reflection) const override
{
GenericComponentWrapper::Reflect(reflection);
}
void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided, const AZ::Component* instance) const override
{
const AZ::ComponentDescriptor* templateDescriptor = GetTemplateDescriptor(instance);
if (templateDescriptor)
{
templateDescriptor->GetProvidedServices(provided, instance);
}
}
void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent, const AZ::Component* instance) const override
{
const AZ::ComponentDescriptor* templateDescriptor = GetTemplateDescriptor(instance);
if (templateDescriptor)
{
templateDescriptor->GetDependentServices(dependent, instance);
}
}
void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required, const AZ::Component* instance) const override
{
const AZ::ComponentDescriptor* templateDescriptor = GetTemplateDescriptor(instance);
if (templateDescriptor)
{
templateDescriptor->GetRequiredServices(required, instance);
}
}
void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible, const AZ::Component* instance) const override
{
const AZ::ComponentDescriptor* templateDescriptor = GetTemplateDescriptor(instance);
if (templateDescriptor)
{
templateDescriptor->GetIncompatibleServices(incompatible, instance);
}
}
};
AZ::ComponentDescriptor* GenericComponentWrapper::CreateDescriptor()
{
AZ::ComponentDescriptor* descriptor = nullptr;
EBUS_EVENT_ID_RESULT(descriptor, GenericComponentWrapper::RTTI_Type(), AZ::ComponentDescriptorBus, GetDescriptor);
return descriptor ? descriptor : aznew GenericComponentWrapperDescriptor();
}
} // namespace Components
const AZ::Uuid& GetUnderlyingComponentType(const AZ::Component& component)
{
return component.GetUnderlyingComponentType();
}
} // namespace AzToolsFramework
@@ -0,0 +1,128 @@
/*
* 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 <AzCore/Slice/SliceBus.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
namespace AzFramework
{
class EditorEntityEvents;
}
namespace AzToolsFramework
{
namespace Components
{
class GenericComponentWrapperDescriptor;
/**
* GenericComponentWrapper wraps around a component in the
* editor. It is used to add components without a specialized
* editor component to an entity.
*/
class GenericComponentWrapper
: public EditorComponentBase
, private AzFramework::EntityDebugDisplayEventBus::Handler
{
public:
AZ_CLASS_ALLOCATOR(GenericComponentWrapper, AZ::SystemAllocator, 0);
AZ_RTTI(GenericComponentWrapper, "{68D358CA-89B9-4730-8BA6-E181DEA28FDE}", EditorComponentBase);
static AZ::ComponentDescriptor* CreateDescriptor();
GenericComponentWrapper();
GenericComponentWrapper(const AZ::SerializeContext::ClassData* templateClassData);
GenericComponentWrapper(AZ::Component* templateClass);
~GenericComponentWrapper();
GenericComponentWrapper(const GenericComponentWrapper& RHS);
GenericComponentWrapper(GenericComponentWrapper&& RHS);
GenericComponentWrapper& operator=(const GenericComponentWrapper& RHS);
GenericComponentWrapper& operator=(GenericComponentWrapper&& RHS);
const char* GetDisplayName();
const char* GetDisplayDescription();
// AZ::Component
void Init() override;
void Activate() override;
void Deactivate() override;
const AZ::TypeId& GetUnderlyingComponentType() const override;
// AzFramework::DebugDisplayRequestBus
void DisplayEntityViewport(
const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay) override;
void BuildGameEntity(AZ::Entity* gameEntity) override;
void SetPrimaryAsset(const AZ::Data::AssetId& assetId) override;
AZ::ComponentValidationResult ValidateComponentRequirements(
const AZ::ImmutableEntityVector& sliceEntities,
const AZStd::unordered_set<AZ::Crc32>& platformTags) const override;
AZ::Component* GetTemplate() const { return m_template; }
/// Forget about, and release ownership of, template component.
AZ::Component* ReleaseTemplate();
static void Reflect(AZ::ReflectContext* context);
protected:
AZ::Component* m_template = nullptr;
AzFramework::EditorEntityEvents* m_templateEvents = nullptr;
AZStd::string m_displayName;
AZStd::string m_displayDescription;
};
} // namespace Components
/// Returns the component's type ID.
/// If the component is a GenericComponentWrapper,
/// then the type ID of the wrapped component is returned.
const AZ::Uuid& GetUnderlyingComponentType(const AZ::Component& component);
/**
* Find the component of the specified type on an entity.
* This function is often used to find components that don't have editor-time counterparts and thus are wrapped in \ref GenericComponentWrapper.
* @param entity The pointer to an entity.
* @return A pointer to the component found on the entity. If multiple components are found the first one is returned.
*/
template <typename ComponentType>
ComponentType* FindWrappedComponentForEntity(const AZ::Entity* entity)
{
if (!entity)
{
return nullptr;
}
AZStd::vector<Components::GenericComponentWrapper*> genericComponentsArray = entity->FindComponents<Components::GenericComponentWrapper>();
if (genericComponentsArray.empty())
{
return nullptr;
}
for (Components::GenericComponentWrapper* genericComponent : genericComponentsArray)
{
auto componentType = GetUnderlyingComponentType(*genericComponent);
if (componentType == azrtti_typeid<ComponentType>())
{
return static_cast<ComponentType*>(genericComponent->GetTemplate());
}
}
return nullptr;
}
} // namespace AzToolsFramework
@@ -0,0 +1,42 @@
/*
* 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 "AzToolsFramework_precompiled.h"
#include "LayerResult.h"
#include <QString>
namespace AzToolsFramework
{
namespace Layers
{
void LayerResult::MessageResult()
{
switch (m_result)
{
case AzToolsFramework::Layers::LayerResultStatus::Success:
// Nothing to message on a success.
break;
case AzToolsFramework::Layers::LayerResultStatus::Error:
AZ_Error("Layer", false, m_message.toUtf8().data());
break;
case AzToolsFramework::Layers::LayerResultStatus::Warning:
AZ_Warning("Layer", false, m_message.toUtf8().data());
break;
default:
AZ_Warning("Layer", false, "Unknown layer error.");
AZ_Error("Layer", false, m_message.toUtf8().data());
break;
}
}
}
}
@@ -0,0 +1,64 @@
/*
* 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
namespace AzToolsFramework
{
namespace Layers
{
enum class LayerResultStatus
{
Success,
Warning,
Error
};
/**
* Holds the status of a layer operation, and a message detailing that status when not a success.
*/
struct LayerResult
{
public:
LayerResult() { }
LayerResult(LayerResultStatus resultStatus, QString resultMessage) :
m_result(resultStatus),
m_message(resultMessage)
{
}
/**
* A helper function to make it obvious at callsites that a success is intended.
*/
static LayerResult CreateSuccess() { return LayerResult(); }
/**
* Returns true if this LayerResult was a success, false if not.
*/
bool IsSuccess() const
{
return m_result == LayerResultStatus::Success;
}
/**
* If a failure occured, outputs the current failure to the appropriate system.
* On success, does nothing.
*/
void MessageResult();
LayerResultStatus m_result = LayerResultStatus::Success;
QString m_message;
};
}
}
@@ -0,0 +1,118 @@
/*
* 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 <AzCore/Script/ScriptProperty.h>
#include <AzFramework/Script/ScriptComponent.h>
#include <AzCore/Script/ScriptContext.h>
#include <AzCore/Script/ScriptAsset.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Debug/TraceMessageBus.h>
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
#include <AzToolsFramework/ToolsComponents/EditorAssetReference.h>
namespace AzToolsFramework
{
namespace Components
{
/**
*
*/
class ScriptEditorComponent
: public AzToolsFramework::Components::EditorComponentBase
, private AZ::Data::AssetBus::Handler
{
public:
AZ_EDITOR_COMPONENT(ScriptEditorComponent, "{b5fc8679-fa2a-4c7c-ac42-dcc279ea613a}")
static bool DoComponentsMatch(const ScriptEditorComponent* thisComponent, const ScriptEditorComponent* otherComponent);
ScriptEditorComponent() = default;
~ScriptEditorComponent() override;
//////////////////////////////////////////////////////////////////////////
// Component
void Init() override;
void Activate() override;
void Deactivate() override;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Editor Component
void BuildGameEntity(AZ::Entity* gameEntity) override;
void SetPrimaryAsset(const AZ::Data::AssetId& /*assetId*/) override;
//////////////////////////////////////////////////////////////////////////
const AZ::Data::Asset<AZ::ScriptAsset>& GetScript() const { return m_scriptComponent.GetScript(); }
void SetScript(const AZ::Data::Asset<AZ::ScriptAsset>& script);
/// Resets the property to it's default value. (TODO)
//void ResetProperty(const char* name);
//////////////////////////////////////////////////////////////////////////
// Data::AssetEvents
void OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
void OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
void OnAssetError(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
//////////////////////////////////////////////////////////////////////////
void LaunchLuaEditor(const AZ::Data::AssetId&, const AZ::Data::AssetType&);
protected:
ScriptEditorComponent(const ScriptEditorComponent&) = delete;
struct ElementInfo
{
AZ::Uuid m_uuid; // Type uuid for the class field that should use this edit data.
AZ::Edit::ElementData m_editData; // Edit metadata (name, description, attribs, etc).
bool m_isAttributeOwner; // True if this ElementInfo owns the internal attributes. We can use a single
// ElementInfo for more than one class field, but only one owns the Attributes.
float m_sortOrder; // Sort order of the property as defined by using the "order" attribute, by default the order is FLT_MAX which means alphabetical sort will be used
};
static void Reflect(AZ::ReflectContext* context);
void LoadProperties();
// make sure internal script (m_scriptComponent.m_script) is set before loading
void LoadScript();
void LoadProperties(AZ::ScriptDataContext& sdc, AzFramework::ScriptPropertyGroup& group);
void RemovedOldProperties(AzFramework::ScriptPropertyGroup& group);
void SortProperties(AzFramework::ScriptPropertyGroup& group);
bool LoadAttribute(AZ::ScriptDataContext& sdc, int valueIndex, const char* name, AZ::Edit::ElementData& ed, AZ::ScriptProperty* prop);
bool LoadDefaultAsset(AZ::ScriptDataContext& sdc, int valueIndex, const char* name, AzFramework::ScriptPropertyGroup& group, ElementInfo& elementInfo);
bool LoadDefaultEntityRef(AZ::ScriptDataContext& sdc, int valueIndex, const char* name, AzFramework::ScriptPropertyGroup& group, ElementInfo& elementInfo);
void ClearDataElements();
AZ::u32 ScriptHasChanged();
bool LoadEnumValuesDouble(AZ::ScriptDataContext& sdc, int valueIndex, AZ::Edit::ElementData& ed);
bool LoadEnumValuesString(AZ::ScriptDataContext& sdc, int valueIndex, AZ::Edit::ElementData& ed);
const AZ::Edit::ElementData* GetDataElement(const void* element, const AZ::Uuid& typeUuid) const;
static const AZ::Edit::ElementData* GetScriptPropertyEditData(const void* handlerPtr, const void* elementPtr, const AZ::Uuid& elementType);
////////////////////////////////////////////////////////////////////////////
const char* CacheString(const char* str);
AZStd::unordered_map<const void*, AZStd::string> m_cachedStrings; ///<- TODO Make editor global as we can chase them across multiple areas
////////////////////////////////////////////////////////////////////////////
AZStd::unordered_map<const void*, ElementInfo> m_dataElements;
AzFramework::ScriptComponent m_scriptComponent;
AZ::Data::Asset<AZ::ScriptAsset> m_scriptAsset;
AZStd::string m_customName;
};
} // namespace Component
} // namespace AzToolsFramework
@@ -0,0 +1,99 @@
/*
* 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 "AzToolsFramework_precompiled.h"
#include "SelectionComponent.h"
#include <AzCore/Serialization/EditContext.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
namespace AzToolsFramework
{
namespace Components
{
SelectionComponent::SelectionComponent()
{
m_currentSelectionFlag = SF_Unselected;
m_currentSelectionAABB = AZ::Aabb::CreateNull();
}
SelectionComponent::~SelectionComponent()
{
}
void SelectionComponent::Init()
{
}
void SelectionComponent::UpdateBounds(const AZ::Aabb& newBounds)
{
m_currentSelectionAABB = newBounds;
}
void SelectionComponent::Activate()
{
SelectionComponentMessages::Bus::Handler::BusConnect(GetEntityId());
AzToolsFramework::EntitySelectionEvents::Bus::Handler::BusConnect(GetEntityId());
}
void SelectionComponent::Deactivate()
{
AzToolsFramework::EntitySelectionEvents::Bus::Handler::BusDisconnect(GetEntityId());
SelectionComponentMessages::Bus::Handler::BusDisconnect(GetEntityId());
m_currentSelectionFlag = SF_Unselected;
}
void SelectionComponent::OnSelected()
{
m_currentSelectionFlag = SF_Selected;
}
void SelectionComponent::OnDeselected()
{
m_currentSelectionFlag = SF_Unselected;
}
bool SelectionComponent::IsSelected() const
{
return (m_currentSelectionFlag & SF_Selected) != 0;
}
bool SelectionComponent::IsPrimarySelection() const
{
return ((m_currentSelectionFlag & SF_Selected) != 0) && ((m_currentSelectionFlag & SF_Primary) != 0);
}
void SelectionComponent::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
// reflect data for script, serialization, editing...
if (serializeContext)
{
serializeContext->Class<SelectionComponent, AZ::Component>()
;
AZ::EditContext* ptrEdit = serializeContext->GetEditContext();
if (ptrEdit)
{
ptrEdit->Class<SelectionComponent>("Selection", "Indicates whether the object is selected or not")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ_CRC("PropertyVisibility_Hide", 0x32ab90f7)) // no point in showing this in the property inspector, its for internal use.
->Attribute(AZ::Edit::Attributes::HideIcon, true);
}
}
}
void SelectionComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("EditorSelectionService", 0x03ef9aae));
}
} // namespace Components
} // namespace AzToolsFramework
@@ -0,0 +1,77 @@
/*
* 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.
*
*/
#ifndef SELECTION_COMPONENT_H_INC
#define SELECTION_COMPONENT_H_INC
#include <AzCore/base.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Math/Crc.h>
#include <AzCore/Math/Aabb.h>
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
#include <AzToolsFramework/ToolsComponents/SelectionComponentBus.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#pragma once
namespace AzToolsFramework
{
namespace Components
{
class SelectionComponent
: public EditorComponentBase
, private SelectionComponentMessages::Bus::Handler
, private AzToolsFramework::EntitySelectionEvents::Bus::Handler
{
public:
friend class SelectionComponentFactory;
AZ_COMPONENT(SelectionComponent, "{73B724FC-43D1-4C75-ACF5-79AA8A3BF89D}", EditorComponentBase)
SelectionComponent();
virtual ~SelectionComponent();
//////////////////////////////////////////////////////////////////////////
// AZ::Component overrides
void Init() override;
void Activate() override;
void Deactivate() override;
//////////////////////////////////////////////////////////////////////////
bool IsSelected() const;
bool IsPrimarySelection() const;
void UpdateBounds(const AZ::Aabb& newBounds);
private:
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
static void Reflect(AZ::ReflectContext* context);
AZ::Aabb m_currentSelectionAABB;
AZ::u32 m_currentSelectionFlag;
//////////////////////////////////////////////////////////////////////////
// EntitySelectionEvents::Bus::Handler overrides
void OnSelected() override;
void OnDeselected() override;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// SelectionComponentMessages::Bus
AZ::Aabb GetSelectionBound() override { return m_currentSelectionAABB; }
//////////////////////////////////////////////////////////////////////////
};
}
} // namespace AzToolsFramework
#endif
@@ -0,0 +1,72 @@
/*
* 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.
*
*/
#ifndef SELECTION_COMPONENT_BUS_H_INC
#define SELECTION_COMPONENT_BUS_H_INC
#include <AzCore/base.h>
#include <AzCore/EBus/EBus.h>
#include <AzCore/Math/Aabb.h>
#pragma once
namespace AzToolsFramework
{
namespace Components
{
class BoundCollector
{
public:
BoundCollector()
{
m_finalAabb = AZ::Aabb::CreateNull();
}
void operator=(const AZ::Aabb& other)
{
if (other.IsValid())
{
m_finalAabb.AddAabb(other);
}
}
AZ::Aabb m_finalAabb;
};
enum SelectionFlags
{
SF_Unselected = 0,
SF_Selected = 1,
SF_Primary = 2,
};
//////////////////////////////////////////////////////////////////////////
// messages FOR transform change notification.
// selection components connect to this bus by Entity ID.
//////////////////////////////////////////////////////////////////////////
class SelectionComponentMessages
: public AZ::EBusTraits
{
public:
using Bus = AZ::EBus<SelectionComponentMessages>;
//////////////////////////////////////////////////////////////////////////
// Bus configuration
typedef AZ::EntityId BusIdType;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; // components have an actual ID that they report back on
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; // every listener registers unordered on this bus
virtual AZ::Aabb GetSelectionBound() { return AZ::Aabb::CreateNull(); }
};
}
} // namespace AzToolsFramework
#endif
@@ -0,0 +1,37 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
namespace AzToolsFramework
{
//! This EBUS is used to tell the assetprocessor about an asset type that should be retrieved from the source instead of the cache
class ToolsAssetSystemRequests :
public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides - Application is a singleton
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
using MutexType = AZStd::recursive_mutex;
//////////////////////////////////////////////////////////////////////////
virtual ~ToolsAssetSystemRequests() = default;
//! Register an asset type that should return a stream to the source instead of the product
virtual void RegisterSourceAssetType(const AZ::Data::AssetType& assetType, const char* assetFileFilter) = 0;
//! Unregister an asset type as a source, reverting to returning the product stream instead
virtual void UnregisterSourceAssetType(const AZ::Data::AssetType& assetType) = 0;
};
using ToolsAssetSystemBus = AZ::EBus<ToolsAssetSystemRequests>;
}
@@ -0,0 +1,243 @@
/*
* 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 <AzCore/Asset/AssetManager.h>
#include <AzCore/IO/SystemFile.h>
#include <AzCore/IO/FileIO.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/ToolsComponents/ToolsAssetCatalogComponent.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/Asset/AssetProcessorMessages.h>
#include <AzFramework/Network/AssetProcessorConnection.h>
namespace AssetProcessor
{
void ToolsAssetCatalogComponent::Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<ToolsAssetCatalogComponent, AZ::Component>()
->Version(1);
}
}
void ToolsAssetCatalogComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("AssetCatalogService", 0xc68ffc57));
}
void ToolsAssetCatalogComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("AssetDatabaseService", 0x3abf5601));
}
void ToolsAssetCatalogComponent::Activate()
{
AZ::Data::AssetCatalogRequestBus::Handler::BusConnect();
}
void ToolsAssetCatalogComponent::Deactivate()
{
AZ::Data::AssetCatalogRequestBus::Handler::BusDisconnect();
DisableCatalog();
}
AZ::Data::AssetStreamInfo ToolsAssetCatalogComponent::GetStreamInfoForLoad(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType)
{
AzFramework::SocketConnection* engineConnection = AzFramework::SocketConnection::GetInstance();
if (!engineConnection || !engineConnection->IsConnected())
{
return {};
}
AzFramework::AssetSystem::AssetInfoRequest request(assetId);
AzFramework::AssetSystem::AssetInfoResponse response;
request.m_assetType = assetType;
request.m_platformName = m_currentPlatform;
if (!SendRequest(request, response))
{
AZ_Error("ToolsAssetCatalogComponent", false, "Failed to send GetAssetInfoById request for %s", assetId.ToString<AZStd::string>().c_str());
return {};
}
if (response.m_found)
{
AZStd::string fullPath;
if(response.m_rootFolder.empty())
{
fullPath = response.m_assetInfo.m_relativePath;
}
else
{
AzFramework::StringFunc::Path::Join(response.m_rootFolder.c_str(), response.m_assetInfo.m_relativePath.c_str(), fullPath);
}
AZ::Data::AssetStreamInfo streamInfo;
streamInfo.m_dataLen = response.m_assetInfo.m_sizeBytes;
streamInfo.m_streamName = fullPath;
streamInfo.m_streamFlags = AZ::IO::OpenMode::ModeRead;
return streamInfo;
}
return {};
}
AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string> ToolsAssetCatalogComponent::GetProductDependencies(
const AZ::Data::AssetId& id,
AzFramework::AssetSystem::AssetDependencyInfoRequest::DependencyType dependencyType,
AzFramework::AssetSystem::AssetDependencyInfoResponse& response)
{
response.m_found = false;
AzFramework::SocketConnection* engineConnection = AzFramework::SocketConnection::GetInstance();
if (!engineConnection || !engineConnection->IsConnected())
{
return AZ::Failure(AZStd::string("No tool connection present."));
}
AzFramework::AssetSystem::AssetDependencyInfoRequest request(id, dependencyType);
if (!SendRequest(request, response))
{
AZ_Error("ToolsAssetCatalogComponent", false, "Failed to send GetProductDependencies request for %s",
id.ToString<AZStd::string>().c_str());
}
if (response.m_found)
{
return AZ::Success(AZStd::move(response.m_dependencies));
}
return AZ::Failure(response.m_errorString);
}
AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string> ToolsAssetCatalogComponent::GetDirectProductDependencies(
const AZ::Data::AssetId& id)
{
AzFramework::AssetSystem::AssetDependencyInfoResponse response;
return GetProductDependencies(
id,
AzFramework::AssetSystem::AssetDependencyInfoRequest::DependencyType::DirectDependencies,
response);
}
AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string> ToolsAssetCatalogComponent::GetAllProductDependencies(
const AZ::Data::AssetId& id)
{
AzFramework::AssetSystem::AssetDependencyInfoResponse response;
return GetProductDependencies(
id,
AzFramework::AssetSystem::AssetDependencyInfoRequest::DependencyType::AllDependencies,
response);
}
AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string> ToolsAssetCatalogComponent::GetLoadBehaviorProductDependencies(
const AZ::Data::AssetId& id, AZStd::unordered_set<AZ::Data::AssetId>& noloadSet,
AZ::Data::PreloadAssetListType& preloadAssetList)
{
AzFramework::AssetSystem::AssetDependencyInfoResponse response;
auto result = GetProductDependencies(
id,
AzFramework::AssetSystem::AssetDependencyInfoRequest::DependencyType::LoadBehaviorDependencies,
response);
// Copy the NoLoad and PreLoad dependency lists out of the response before returning.
noloadSet = response.m_noloadSet;
preloadAssetList = response.m_preloadAssetList;
return result;
}
void ToolsAssetCatalogComponent::EnableCatalogForAsset(const AZ::Data::AssetType& assetType)
{
AZ_Assert(AZ::Data::AssetManager::IsReady(), "Asset manager is not ready.");
AZ::Data::AssetManager::Instance().RegisterCatalog(this, assetType);
}
void ToolsAssetCatalogComponent::DisableCatalog()
{
if (AZ::Data::AssetManager::IsReady())
{
AZ::Data::AssetManager::Instance().UnregisterCatalog(this);
}
}
void ToolsAssetCatalogComponent::SetActivePlatform(const AZStd::string& platform)
{
m_currentPlatform = platform;
}
AZStd::string ToolsAssetCatalogComponent::GetAssetPathById(const AZ::Data::AssetId& id)
{
return GetAssetInfoById(id).m_relativePath;
}
AZ::Data::AssetId ToolsAssetCatalogComponent::GetAssetIdByPath(
const char* path,
const AZ::Data::AssetType& typeToRegister,
bool autoRegisterIfNotFound)
{
AZ_UNUSED(autoRegisterIfNotFound);
AZ_Assert(autoRegisterIfNotFound == false, "Auto registration is invalid during asset processing.");
AZ_UNUSED(typeToRegister);
AZ_Assert(typeToRegister == AZ::Data::s_invalidAssetType, "Can not register types during asset processing.");
AzFramework::SocketConnection* engineConnection = AzFramework::SocketConnection::GetInstance();
if (!engineConnection || !engineConnection->IsConnected())
{
return {};
}
AzFramework::AssetSystem::AssetInfoRequest request(path);
AzFramework::AssetSystem::AssetInfoResponse response;
request.m_platformName = m_currentPlatform;
if (!SendRequest(request, response))
{
AZ_Error("ToolsAssetCatalogComponent", false, "Failed to send GetAssetIdByPath request for %s", path);
return {};
}
return response.m_assetInfo.m_assetId;
}
AZ::Data::AssetInfo ToolsAssetCatalogComponent::GetAssetInfoById(const AZ::Data::AssetId& id)
{
AzFramework::SocketConnection* engineConnection = AzFramework::SocketConnection::GetInstance();
if (!engineConnection || !engineConnection->IsConnected())
{
return {};
}
AzFramework::AssetSystem::AssetInfoRequest request(id);
AzFramework::AssetSystem::AssetInfoResponse response;
request.m_platformName = m_currentPlatform;
if (!SendRequest(request, response))
{
AZ_Error("ToolsAssetCatalogComponent", false, "Failed to send GetAssetInfoById request for %s", id.ToString<AZStd::string>().c_str());
return {};
}
return response.m_assetInfo;
}
}
@@ -0,0 +1,90 @@
/*
* 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 <AzCore/Asset/AssetManagerBus.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Asset/AssetTypeInfoBus.h>
#include <AzToolsFramework/Asset/AssetProcessorMessages.h>
namespace AssetProcessor
{
class IToolsAssetCatalog
{
public:
AZ_TYPE_INFO(IToolsAssetCatalog, "{F8BF6237-5BD5-46C9-9589-EA041BA4534C}");
IToolsAssetCatalog() = default;
virtual void SetActivePlatform(const AZStd::string& platform) = 0;
AZ_DISABLE_COPY_MOVE(IToolsAssetCatalog);
};
//! Tools replacement for the AssetCatalogComponent
//! Services the AssetCatalogRequestBus by interfacing with the AssetProcessor over a network connection
class ToolsAssetCatalogComponent :
public AZ::Component,
public AZ::Interface<IToolsAssetCatalog>::Registrar,
public AZ::Data::AssetCatalogRequestBus::Handler,
public AZ::Data::AssetCatalog
{
public:
AZ_COMPONENT(ToolsAssetCatalogComponent, "{AE68E46B-0E21-499A-8309-41408BCBE4BF}");
ToolsAssetCatalogComponent() = default;
~ToolsAssetCatalogComponent() override = default;
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& services);
void Activate() override;
void Deactivate() override;
// AssetCatalog overrides
AZ::Data::AssetStreamInfo GetStreamInfoForLoad(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType) override;
AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string> GetDirectProductDependencies(
const AZ::Data::AssetId& id) override;
AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string> GetAllProductDependencies(
const AZ::Data::AssetId& id) override;
AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string> GetLoadBehaviorProductDependencies(
const AZ::Data::AssetId& id, AZStd::unordered_set<AZ::Data::AssetId>& noloadSet,
AZ::Data::PreloadAssetListType& preloadAssetList) override;
////////////////////////////////////////////////////////////////////////////////
// AssetCatalogRequestBus overrides
AZStd::string GetAssetPathById(const AZ::Data::AssetId& id) override;
AZ::Data::AssetId GetAssetIdByPath(const char* path, const AZ::Data::AssetType& typeToRegister, bool autoRegisterIfNotFound) override;
AZ::Data::AssetInfo GetAssetInfoById(const AZ::Data::AssetId& id) override;
void EnableCatalogForAsset(const AZ::Data::AssetType& assetType) override;
void DisableCatalog() override;
////////////////////////////////////////////////////////////////////////////////
// IToolsAssetCatalog overrides
void SetActivePlatform(const AZStd::string& platform) override;
////////////////////////////////////////////////////////////////////////////////
protected:
AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string> GetProductDependencies(
const AZ::Data::AssetId& id,
AzFramework::AssetSystem::AssetDependencyInfoRequest::DependencyType dependencyType,
AzFramework::AssetSystem::AssetDependencyInfoResponse& response);
// Keeps track of the currently active platform - the platform for the currently processing ProcessJob request
AZStd::string m_currentPlatform;
};
}
@@ -0,0 +1,265 @@
/*
* 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 <AzCore/Component/Component.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Component/EntityBus.h>
#include <AzCore/Component/EntityId.h>
#include <AzCore/Slice/SliceBus.h>
#include <AzFramework/Components/TransformComponent.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzToolsFramework/API/ComponentEntitySelectionBus.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/Commands/SelectionCommand.h>
#include "EditorComponentBase.h"
#include "TransformComponentBus.h"
namespace AzToolsFramework
{
namespace Components
{
/// Manages transform data as separate vector fields for editing purposes.
/// The TransformComponent is referenced by other components in the same entity, it is not an asset.
class TransformComponent
: public EditorComponentBase
, public AZ::TransformBus::Handler
, public AZ::SliceEntityHierarchyRequestBus::Handler
, private TransformComponentMessages::Bus::Handler
, private AZ::EntityBus::Handler
, private AZ::TransformNotificationBus::MultiHandler
, private AZ::TransformHierarchyInformationBus::Handler
{
public:
friend class TransformComponentFactory;
AZ_EDITOR_COMPONENT(TransformComponent, AZ::EditorTransformComponentTypeId, EditorComponentBase, AZ::SliceEntityHierarchyInterface, AZ::TransformInterface)
TransformComponent();
virtual ~TransformComponent();
// AZ::Component
void Init() override;
void Activate() override;
void Deactivate() override;
static void PasteOverComponent(const TransformComponent* sourceComponent, TransformComponent* destinationComponent);
// AZ::EntityBus
void OnEntityActivated(const AZ::EntityId& parentEntityId) override;
void OnEntityDeactivated(const AZ::EntityId& parentEntityId) override;
// AZ::TransformBus
const AZ::Transform& GetLocalTM() override;
void SetLocalTM(const AZ::Transform& tm) override;
const AZ::Transform& GetWorldTM() override;
void SetWorldTM(const AZ::Transform& tm) override;
void GetLocalAndWorld(AZ::Transform& localTM, AZ::Transform& worldTM) override;
// Translation modifiers
void SetWorldTranslation(const AZ::Vector3& newPosition) override;
void SetLocalTranslation(const AZ::Vector3& newPosition) override;
AZ::Vector3 GetWorldTranslation() override;
AZ::Vector3 GetLocalTranslation() override;
void MoveEntity(const AZ::Vector3& offset) override;
void SetWorldX(float newX) override;
void SetWorldY(float newY) override;
void SetWorldZ(float newZ) override;
float GetWorldX() override;
float GetWorldY() override;
float GetWorldZ() override;
void SetLocalX(float x) override;
void SetLocalY(float y) override;
void SetLocalZ(float z) override;
float GetLocalX() override;
float GetLocalY() override;
float GetLocalZ() override;
// Rotation modifiers
void SetRotation(const AZ::Vector3& eulerAnglesRadians) override;
void SetRotationQuaternion(const AZ::Quaternion& quaternion) override;
void SetRotationX(float eulerAngleRadians) override;
void SetRotationY(float eulerAngleRadians) override;
void SetRotationZ(float eulerAngleRadians) override;
void RotateByX(float eulerAngleRadians) override;
void RotateByY(float eulerAngleRadians) override;
void RotateByZ(float eulerAngleRadians) override;
AZ::Vector3 GetRotationEulerRadians() override;
AZ::Quaternion GetRotationQuaternion() override;
float GetRotationX() override;
float GetRotationY() override;
float GetRotationZ() override;
AZ::Vector3 GetWorldRotation() override;
AZ::Quaternion GetWorldRotationQuaternion() override;
void SetLocalRotation(const AZ::Vector3& eulerAnglesRadian) override;
void SetLocalRotationQuaternion(const AZ::Quaternion& quaternion) override;
void RotateAroundLocalX(float eulerAngleRadian) override;
void RotateAroundLocalY(float eulerAngleRadian) override;
void RotateAroundLocalZ(float eulerAngleRadian) override;
AZ::Vector3 GetLocalRotation() override;
AZ::Quaternion GetLocalRotationQuaternion() override;
// Scale Modifiers
void SetScale(const AZ::Vector3& newScale) override;
void SetScaleX(float newScale) override;
void SetScaleY(float newScale) override;
void SetScaleZ(float newScale) override;
AZ::Vector3 GetScale() override;
float GetScaleX() override;
float GetScaleY() override;
float GetScaleZ() override;
void SetLocalScale(const AZ::Vector3& scale) override;
void SetLocalScaleX(float scaleX) override;
void SetLocalScaleY(float scaleY) override;
void SetLocalScaleZ(float scaleZ) override;
AZ::Vector3 GetLocalScale() override;
AZ::Vector3 GetWorldScale() override;
AZ::EntityId GetParentId() override;
AZ::TransformInterface* GetParent() override;
void SetParent(AZ::EntityId parentId) override;
void SetParentRelative(AZ::EntityId parentId) override;
AZStd::vector<AZ::EntityId> GetChildren() override;
AZStd::vector<AZ::EntityId> GetAllDescendants() override;
AZStd::vector<AZ::EntityId> GetEntityAndAllDescendants() override;
bool IsStaticTransform() override;
void SetIsStaticTransform(bool isStatic) override;
// TransformComponentMessages::Bus
void TranslateBy(const AZ::Vector3&) override;
void RotateBy(const AZ::Vector3&) override; // euler in degrees
void ScaleBy(const AZ::Vector3&) override;
const EditorTransform& GetLocalEditorTransform() override;
void SetLocalEditorTransform(const EditorTransform& dest) override;
bool IsTransformLocked() override;
/// \return true if the entity is a root-level entity (has no transform parent).
bool IsRootEntity() const { return !m_parentEntityId.IsValid(); }
//callable is a lambda taking a AZ::EntityId and returning nothing, will be called with the id of each child
//Also will be called for children of children, all the way down the hierarchy
template<typename Callable>
void ForEachChild(Callable callable)
{
for (auto childId : m_childrenEntityIds)
{
callable(childId);
auto child = GetTransformComponent(childId);
if (child)
{
child->ForEachChild(callable);
}
}
}
void BuildGameEntity(AZ::Entity* gameEntity) override;
void UpdateCachedWorldTransform();
void ClearCachedWorldTransform();
bool IsPositionInterpolated() override;
bool IsRotationInterpolated() override;
// SliceEntityHierarchyRequestBus
AZ::EntityId GetSliceEntityParentId() override;
AZStd::vector<AZ::EntityId> GetSliceEntityChildren() override;
private:
// AZ::TransformNotificationBus - Connected to parent's ID
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
void OnTransformChanged(); //convenience
// TransformHierarchyInformationBus
void GatherChildren(AZStd::vector<AZ::EntityId>& children) override;
void AddContextMenuActions(QMenu* menu) override;
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
static void Reflect(AZ::ReflectContext* context);
AZ::Outcome<void, AZStd::string> ValidatePotentialParent(void* newValue, const AZ::Uuid& valueType);
AZ::u32 ParentChanged();
AZ::u32 TransformChanged();
AZ::u32 StaticChanged();
AZ::Transform GetLocalTranslationTM() const;
AZ::Transform GetLocalRotationTM() const;
AZ::Transform GetLocalScaleTM() const;
TransformComponent* GetParentTransformComponent() const;
TransformComponent* GetTransformComponent(AZ::EntityId otherEntityId) const;
bool IsEntityInHierarchy(AZ::EntityId entityId);
void SetParentImpl(AZ::EntityId parentId, bool relative);
const AZ::Transform& GetParentWorldTM() const;
void ModifyEditorTransform(AZ::Vector3& vec, const AZ::Vector3& data, const AZ::Transform& parentInverse);
void CheckApplyCachedWorldTransform(const AZ::Transform& parentWorld);
bool m_isStatic;
AZ::EntityId m_parentEntityId;
AZ::EntityId m_previousParentEntityId;
EditorTransform m_editorTransform;
//these are only used to hold onto the references returned by GetLocalTM and GetWorldTM
AZ::Transform m_localTransformCache;
AZ::Transform m_worldTransformCache;
// Drives transform behavior when parent activates. See AZ::TransformConfig::ParentActivationTransformMode for details.
AZ::TransformConfig::ParentActivationTransformMode m_parentActivationTransformMode;
// Keeping a world transform along with a parent Id at the time of capture.
// This is required for dealing with external changes to parent assignment (i.e. slice propagation).
// A local transform alone isn't enough, since we may have serialized a parent-relative local transform,
// but detached from the parent via propagation of the parent Id field. In such a case, we need to
// know to not erroneously apply the local-space transform we serialized in a world-space capacity.
AZ::Transform m_cachedWorldTransform;
AZ::EntityId m_cachedWorldTransformParent;
EntityIdList m_childrenEntityIds;
bool m_suppressTransformChangedEvent;
bool m_localTransformDirty = true;
bool m_worldTransformDirty = true;
// Used to serialize data required for NetBindable
bool m_netSyncEnabled;
AZ::InterpolationMode m_interpolatePosition;
AZ::InterpolationMode m_interpolateRotation;
};
}
} // namespace AzToolsFramework
@@ -0,0 +1,75 @@
/*
* 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.
*
*/
#ifndef TRANSFORMCOMPONENTBUS_H_
#define TRANSFORMCOMPONENTBUS_H_
#include <AzCore/base.h>
#include <AzCore/Math/Transform.h>
#pragma once
namespace AzToolsFramework
{
namespace Components
{
//////////////////////////////////////////////////////////////////////////
// Manages transform data as separate vector fields for editing purposes.
struct EditorTransform
{
AZ_TYPE_INFO(EditorTransform, "{B02B7063-D238-4F40-A724-405F7A6D68CB}")
EditorTransform()
{
m_translate = AZ::Vector3::CreateZero();
m_scale = AZ::Vector3::CreateOne();
m_rotate = AZ::Vector3::CreateZero();
m_locked = false;
}
static EditorTransform Identity()
{
return EditorTransform();
}
AZ::Vector3 m_translate; //! Translation in engine units (meters)
AZ::Vector3 m_scale;
AZ::Vector3 m_rotate; //! Rotation in degrees
bool m_locked;
};
//////////////////////////////////////////////////////////////////////////
// messages controlling or polling the hierarchy
//////////////////////////////////////////////////////////////////////////
class TransformComponentMessages
: public AZ::ComponentBus
{
public:
using Bus = AZ::EBus<TransformComponentMessages>;
//////////////////////////////////////////////////////////////////////////
// Bus configuration
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; // every listener registers unordered on this bus
virtual const EditorTransform& GetLocalEditorTransform() = 0;
virtual void SetLocalEditorTransform(const EditorTransform& dest) = 0;
virtual void TranslateBy(const AZ::Vector3&) = 0;
virtual void RotateBy(const AZ::Vector3&) = 0;
virtual void ScaleBy(const AZ::Vector3&) = 0;
virtual bool IsTransformLocked() = 0;
};
} // namespace Components
} // namespace AzToolsFramework
#endif // TRANSFORMCOMPONENTBUS_H_