Skip to content
7 changes: 7 additions & 0 deletions Code/Framework/AzCore/AzCore/Component/Component.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ namespace AZ
*/
void SetId(const ComponentId& id) { m_id = id; }

virtual void SetAlias(const AZStd::string&){};

virtual AZStd::string GetAlias()
{
return AZStd::string();
}

/**
* Override to conduct per-component or per-slice validation logic during slice asset processing.
* @param sliceEntities All entities that belong to the slice that the entity with this component is on.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ namespace AZ
if (component && (component->GetUnderlyingComponentType() != genericComponentWrapperTypeId))
{
entityInstance->m_components.emplace_back(component);
component->SetAlias(componentKey);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ namespace AZ::DocumentPropertyEditor
{
BeginLabel();
Attribute(Nodes::Label::Value, text);
Attribute(Nodes::PropertyEditor::SharePriorColumn, true);
Attribute(Nodes::PropertyEditor::Alignment, Nodes::PropertyEditor::Align::AlignLeft);
EndLabel();
}
} // namespace AZ::DocumentPropertyEditor
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ namespace AZ::DocumentPropertyEditor::Nodes
system->RegisterNodeAttribute<ContainerActionButton>(ContainerActionButton::Action);
system->RegisterNodeAttribute<ContainerActionButton>(ContainerActionButton::OnActivate);

system->RegisterPropertyEditor<OverrideIcon>();

system->RegisterPropertyEditor<CheckBox>();
system->RegisterPropertyEditor<Color>();
system->RegisterPropertyEditor<ComboBox>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,11 @@ namespace AZ::DocumentPropertyEditor::Nodes
static constexpr auto OnActivate = CallbackAttributeDefinition<void()>("OnActivate");
};

struct OverrideIcon : PropertyEditorDefinition
{
static constexpr AZStd::string_view Name = "OverrideIcon";
};

struct CheckBox : PropertyEditorDefinition
{
static constexpr AZStd::string_view Name = "CheckBox";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ namespace AZ::Reflection
nullptr);

const StackEntry& nodeData = m_stack.back();
m_serializeContext->EnumerateInstance(&context, nodeData.m_instance, nodeData.m_typeId, nullptr, nullptr);
m_serializeContext->EnumerateInstance(&context, nodeData.m_instance, nodeData.m_typeId, nodeData.m_classData, nodeData.m_classElement);
}

bool BeginNode(
Expand All @@ -254,7 +254,7 @@ namespace AZ::Reflection
else if (classElement)
{
AZStd::string_view elementName = classElement->m_name;
if (!elementName.empty())
if (!elementName.empty() && classElement->m_editData)
{
path.append("/");
path.append(elementName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
*
*/

#pragma optimize("", off)
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/DOM/Backends/JSON/JsonSerializationUtils.h>
#include <AzCore/DOM/DomPrefixTree.h>
#include <AzCore/DOM/DomUtils.h>
#include <AzCore/std/ranges/ranges_algorithm.h>
#include <AzFramework/DocumentPropertyEditor/AdapterBuilder.h>
#include <AzFramework/DocumentPropertyEditor/PropertyEditorNodes.h>
#include <AzFramework/DocumentPropertyEditor/Reflection/LegacyReflectionBridge.h>
#include <AzFramework/DocumentPropertyEditor/ReflectionAdapter.h>
Expand Down Expand Up @@ -355,6 +356,7 @@ namespace AZ::DocumentPropertyEditor

if (!parentContainer->IsFixedSize())
{
[[maybe_unused]] auto serializedPathAttribute = attributes.Find(AZ::Reflection::DescriptorAttributes::SerializedPath);
m_builder.BeginPropertyEditor<Nodes::ContainerActionButton>();
m_builder.Attribute(Nodes::PropertyEditor::SharePriorColumn, true);
m_builder.Attribute(Nodes::PropertyEditor::UseMinimumWidth, true);
Expand Down Expand Up @@ -384,6 +386,10 @@ namespace AZ::DocumentPropertyEditor

m_builder.BeginRow();

AZ::Reflection::AttributeDataType serializedPathAttribute =
attributes.Find(AZ::Reflection::DescriptorAttributes::SerializedPath);
m_adapter->AddIconIfPropertyOverride(&m_builder, serializedPathAttribute.GetString());

for (const auto& attribute : Nodes::Row::RowAttributes)
{
auto attributeValue = attributes.Find(attribute->GetName());
Expand Down Expand Up @@ -473,47 +479,90 @@ namespace AZ::DocumentPropertyEditor
m_builder.Label(labelAttribute.data());
}

AZ::Dom::Value instancePointerValue = AZ::Dom::Utils::MarshalTypedPointerToValue(access.Get(), access.GetType());
bool hashValue = false;
const AZ::Name PointerTypeFieldName = AZ::Dom::Utils::PointerTypeFieldName;
if (instancePointerValue.IsOpaqueValue() || instancePointerValue.FindMember(PointerTypeFieldName))
if (serializedPathAttribute.GetString().empty())
{
hashValue = true;
AZ::Dom::Value instancePointerValue = AZ::Dom::Utils::MarshalTypedPointerToValue(access.Get(), access.GetType());
VisitValue(
instancePointerValue,
access.Get(),
attributes,
// this needs to write the value back into the reflected object via Json serialization
[valuePointer = access.Get(), valueType = access.GetType(), this](const Dom::Value& newValue)
{
// marshal this new value into a pointer for use by the Json serializer
auto marshalledPointer = AZ::Dom::Utils::TryMarshalValueToPointer(newValue, valueType);

rapidjson::Document buffer;
JsonSerializerSettings serializeSettings;
JsonDeserializerSettings deserializeSettings;
serializeSettings.m_serializeContext = m_serializeContext;
deserializeSettings.m_serializeContext = m_serializeContext;

// serialize the new value to Json, using the original valuePointer as a reference object to generate a minimal diff
JsonSerialization::Store(buffer, buffer.GetAllocator(), marshalledPointer, valuePointer, valueType, serializeSettings);

// now deserialize that value into the original location
JsonSerialization::Load(valuePointer, valueType, buffer, deserializeSettings);

// NB: the returned value for serialized pointer values is instancePointerValue, but since this is passed by pointer,
// it will not actually detect a changed dom value. Since we are already writing directly to the DOM before this step,
// it won't affect the calling DPE, however, other DPEs pointed at the same adapter would be unaware of the change,
// and wouldn't update their UI.
// In future, to properly support multiple DPEs on one adapter, we will need to solve this. One way would be to store
// the json serialized value (which is mostly human-readable text) as an attribute, so any change to the Json would
// trigger an update. This would have the advantage of allowing opaque and pointer types to be searchable by the
// string-based Filter adapter. Without this, things like Vector3 will not have searchable values by text. These
// advantages would have to be measured against the size changes in the DOM and the time taken to populate and parse them. return newValue;
return newValue;
},
false,
false);
}
VisitValue(
instancePointerValue,
access.Get(),
attributes,
// this needs to write the value back into the reflected object via Json serialization
[valuePointer = access.Get(), valueType = access.GetType(), this](const Dom::Value& newValue)
{
// marshal this new value into a pointer for use by the Json serializer
auto marshalledPointer = AZ::Dom::Utils::TryMarshalValueToPointer(newValue, valueType);

rapidjson::Document buffer;
JsonSerializerSettings serializeSettings;
JsonDeserializerSettings deserializeSettings;
serializeSettings.m_serializeContext = m_serializeContext;
deserializeSettings.m_serializeContext = m_serializeContext;

// serialize the new value to Json, using the original valuePointer as a reference object to generate a minimal diff
JsonSerialization::Store(buffer, buffer.GetAllocator(), marshalledPointer, valuePointer, valueType, serializeSettings);

// now deserialize that value into the original location
JsonSerialization::Load(valuePointer, valueType, buffer, deserializeSettings);

// NB: the returned value for serialized pointer values is instancePointerValue, but since this is passed by pointer,
// it will not actually detect a changed dom value. Since we are already writing directly to the DOM before this step,
// it won't affect the calling DPE, however, other DPEs pointed at the same adapter would be unaware of the change,
// and wouldn't update their UI.
// In future, to properly support multiple DPEs on one adapter, we will need to solve this. One way would be to store
// the json serialized value (which is mostly human-readable text) as an attribute, so any change to the Json would
// trigger an update. This would have the advantage of allowing opaque and pointer types to be searchable by the
// string-based Filter adapter. Without this, things like Vector3 will not have searchable values by text. These
// advantages would have to be measured against the size changes in the DOM and the time taken to populate and parse them.
return newValue;
},
false, hashValue);
else
{
const AZ::TypeId opaqueType = access.GetType();
[[maybe_unused]] void* pointerFromAccess = access.Get();
AZ::Dom::Value instancePointerValue1 = AZ::Dom::Utils::MarshalTypedPointerToValue(access.Get(), access.GetType());
void* marshalledPointer = AZ::Dom::Utils::TryMarshalValueToPointer(instancePointerValue1, opaqueType);
// TODO: The below 2 lines can be removed. serialize context somehow gets picked up even if you don't explicitly pass it
// here.
JsonSerializerSettings serializeSettings;
serializeSettings.m_serializeContext = m_serializeContext;

rapidjson::Document serializedValue;
auto result = JsonSerialization::Store(
serializedValue, serializedValue.GetAllocator(), marshalledPointer, nullptr, opaqueType, serializeSettings);

AZ::Dom::Value instancePointerValue;
auto outputWriter = instancePointerValue.GetWriteHandler();
auto convertToAzDomResult =
AZ::Dom::Json::VisitRapidJsonValue(serializedValue, *outputWriter, AZ::Dom::Lifetime::Temporary);
VisitValue(
instancePointerValue,
access.Get(),
attributes,
[valuePointer = access.Get(), opaqueType, this](const Dom::Value& newValue)
{
void* marshalledPointer = AZ::Dom::Utils::TryMarshalValueToPointer(newValue, opaqueType);
rapidjson::Document serializedValue;
auto result = JsonSerialization::Store(
serializedValue, serializedValue.GetAllocator(), marshalledPointer, nullptr, opaqueType);

JsonDeserializerSettings deserializeSettings;
deserializeSettings.m_serializeContext = m_serializeContext;
// now deserialize that value into the original location
JsonSerialization::Load(valuePointer, opaqueType, serializedValue, deserializeSettings);

AZ::Dom::Value newInstancePointerValue;
auto outputWriter = newInstancePointerValue.GetWriteHandler();
auto convertToAzDomResult =
AZ::Dom::Json::VisitRapidJsonValue(serializedValue, *outputWriter, AZ::Dom::Lifetime::Temporary);
return newInstancePointerValue;
},
false,
false);
}

}
}

Expand Down Expand Up @@ -864,3 +913,4 @@ namespace AZ::DocumentPropertyEditor
);
}
} // namespace AZ::DocumentPropertyEditor
#pragma optimize("", on)
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@

#pragma once

#include <AzFramework/DocumentPropertyEditor/AdapterBuilder.h>
#include <AzFramework/DocumentPropertyEditor/RoutingAdapter.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/string/string_view.h>

namespace AZ::DocumentPropertyEditor
{
Expand Down Expand Up @@ -60,6 +62,10 @@ namespace AZ::DocumentPropertyEditor
//! property editor instances has altered its value.
void NotifyPropertyChanged(const PropertyChangeInfo& changeInfo);

virtual void AddIconIfPropertyOverride(AdapterBuilder*, const AZStd::string_view&)
{
}

void* GetInstance() { return m_instance; }
const void* GetInstance() const { return m_instance; }
AZ::TypeId GetTypeId() const { return m_typeId; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,15 @@ namespace AzToolsFramework
}
}

bool PrefabOverridePublicHandler::AreOverridesPresent(AZ::EntityId entityId)
bool PrefabOverridePublicHandler::AreOverridesPresent(AZ::EntityId entityId, const AZ::Dom::Path& prefix)
{
AZStd::pair<AZ::Dom::Path, LinkId> pathAndLinkIdPair = GetPathAndLinkIdFromFocusedPrefab(entityId);
if (!pathAndLinkIdPair.first.IsEmpty() && pathAndLinkIdPair.second != InvalidLinkId)
{
if (!prefix.IsEmpty())
{
pathAndLinkIdPair.first /= prefix;
}
return m_prefabOverrideHandler.AreOverridesPresent(pathAndLinkIdPair.first, pathAndLinkIdPair.second);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ namespace AzToolsFramework
//! this function specifically checks for overrides from the focused prefab.
//! @param entityId The id of the entity to check for overrides.
//! @return true if overrides are present on the given entity id from the focused prefab.
bool AreOverridesPresent(AZ::EntityId entityId) override;
bool AreOverridesPresent(AZ::EntityId entityId, const AZ::Dom::Path& prefix = {}) override;

//! Gets the override type on the given entity id. Overrides can come from any ancestor prefab but
//! this function specifically checks for overrides from the focused prefab.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#pragma once

#include <AzCore/Component/EntityId.h>
#include <AzCore/DOM/DomPath.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzToolsFramework/Prefab/Overrides/PrefabOverrideTypes.h>

Expand All @@ -25,7 +26,7 @@ namespace AzToolsFramework
//! by the class implmenting this interface based on certain selections in the editor. eg: the prefab currently being edited.
//! @param entityId The id of the entity to check for overrides.
//! @return true if overrides are present on the given entity id.
virtual bool AreOverridesPresent(AZ::EntityId entityId) = 0;
virtual bool AreOverridesPresent(AZ::EntityId entityId, const AZ::Dom::Path& prefix = {}) = 0;

//! Gets the override type on the given entity id. The prefab that creates the overrides is identified
//! by the class implmenting this interface based on certain selections in the editor. eg: the prefab currently being edited.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@ namespace AzToolsFramework
virtual void Deactivate() override;
//////////////////////////////////////////////////////////////////////////

void SetAlias(const AZStd::string& alias) override
{
m_alias = alias;
}

AZStd::string GetAlias() override
{
return m_alias;
}

/**
* Gets the transform interface of the entity that the component
* belongs to, if the entity has a transform component.
Expand Down Expand Up @@ -191,6 +201,7 @@ namespace AzToolsFramework
static void Reflect(AZ::ReflectContext* context);

private:
AZStd::string m_alias;
AZ::TransformInterface* m_transform;
};

Expand Down
Loading