CustomProperties

CustomProperties

#Overview

name: CustomProperties

The value of this variable can be defined or overridden in .ini config files. 1 .ini config file referencing this setting variable.

It is referenced in 20 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of CustomProperties is to handle custom property data in various Unreal Engine 5 subsystems and plugins. It is used for different purposes across multiple modules, including:

  1. Rider Source Code Access: It is used to parse custom properties from a JSON file for the Rider IDE integration.

  2. PCG (Procedural Content Generation): It is used in the PCG plugin to manage dynamic input pins for PCG settings.

  3. Editor: It is used in the UnrealEd module for custom property color handling and importing custom properties for objects.

  4. Core UObject: It is used in the serialization process for declaring custom versions.

  5. Iris Networking: It is used in the Iris networking system for handling custom replication fragments.

  6. MovieScene: It is used extensively in the MovieScene module for managing custom property accessors and values in the entity system.

The value of this variable is typically set through configuration files, JSON parsing, or programmatically during runtime, depending on the specific use case.

CustomProperties often interacts with other variables and systems specific to its context. For example, in the PCG system, it interacts with dynamic input pins, while in the MovieScene system, it interacts with property accessors and entity allocations.

Developers must be aware that CustomProperties is used differently across various subsystems, and its implementation may vary. It’s crucial to understand the specific context and requirements of the subsystem you’re working with when using CustomProperties.

Best practices when using CustomProperties include:

  1. Ensure proper initialization and cleanup of custom properties.
  2. Validate custom properties before using them, especially when importing from external sources.
  3. Follow the specific guidelines and patterns established for each subsystem that uses CustomProperties.
  4. When extending systems that use CustomProperties, maintain consistency with the existing implementation to avoid conflicts.
  5. Document any custom property usage thoroughly to help other developers understand their purpose and behavior.

#Setting Variables

#References In INI files

Location: <Workspace>/Engine/Config/BaseEditorSettings.ini:48, section: [/Script/UnrealEd.PropertyColorSettings]

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Plugins/Developer/RiderSourceCodeAccess/Source/RiderSourceCodeAccess/Private/RiderPathLocator/Common/RiderPathLocator.cpp:140

Scope (from outer to inner):

file
function     void FRiderPathLocator::ParseProductInfoJson

Source code excerpt:

		}

		const TArray< TSharedPtr<FJsonValue> >* CustomProperties;
		if(!JsonObject->TryGetArrayField(TEXT("customProperties"), CustomProperties)) return;

		for (const TSharedPtr<FJsonValue>& CustomProperty : *CustomProperties)
		{
			const TSharedPtr<FJsonObject> Item = CustomProperty->AsObject();
			if(!Item.IsValid()) continue;
			
			FString SupportUprojectStateKey;
			const bool bIsValidKey = Item->TryGetStringField(TEXT("key"), SupportUprojectStateKey);

#Loc: <Workspace>/Engine/Plugins/PCG/Source/PCG/Private/PCGSettingsWithDynamicInputs.cpp:59

Scope (from outer to inner):

file
function     void UPCGSettingsWithDynamicInputs::AddDynamicInputPin

Source code excerpt:



void UPCGSettingsWithDynamicInputs::AddDynamicInputPin(FPCGPinProperties&& CustomProperties)
{
	if (CustomPropertiesAreValid(CustomProperties))
	{
		DynamicInputPinProperties.Emplace(std::forward<FPCGPinProperties>(CustomProperties));
		OnSettingsChangedDelegate.Broadcast(this, EPCGChangeType::Node | EPCGChangeType::Settings);
	}
}
#endif // WITH_EDITOR

TArray<FPCGPinProperties> UPCGSettingsWithDynamicInputs::StaticInputPinProperties() const

#Loc: <Workspace>/Engine/Plugins/PCG/Source/PCG/Public/PCGSettingsWithDynamicInputs.h:19

Scope (from outer to inner):

file
class        class UPCGSettingsWithDynamicInputs: public UPCGSettings
function     virtual bool CustomPropertiesAreValid

Source code excerpt:

#if WITH_EDITOR
	/** Validate custom pin properties */
	virtual bool CustomPropertiesAreValid(const FPCGPinProperties& CustomProperties) { return true; }
	
	/** User driven event to add a dynamic source pin */
	virtual void OnUserAddDynamicInputPin();
	/** Overridden logic to add a default source pin */
	virtual void AddDefaultDynamicInputPin() PURE_VIRTUAL(PCGDynamicSettings::AddDefaultSourcePin, );
	/** Check if the pin to remove is dynamic */

#Loc: <Workspace>/Engine/Plugins/PCG/Source/PCG/Public/PCGSettingsWithDynamicInputs.h:39

Scope (from outer to inner):

file
class        class UPCGSettingsWithDynamicInputs: public UPCGSettings

Source code excerpt:

#if WITH_EDITOR
	/** Add a new dynamic source pin with the specified properties */
	void AddDynamicInputPin(FPCGPinProperties&& CustomProperties);
#endif // WITH_EDITOR

	/** The input pin properties that are statically defined by the client class */
	virtual TArray<FPCGPinProperties> StaticInputPinProperties() const;

	/** Dynamic pin properties that the user can add or remove from */

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/EditorEngine.cpp:528

Scope (from outer to inner):

file
function     UEditorEngine::UEditorEngine

Source code excerpt:

			});

		for (const FPropertyColorCustomProperty& PropertyColorCustomProperty : GetDefault<UPropertyColorSettings>()->CustomProperties)
		{
			FActorPrimitiveColorHandler::Get().RegisterPrimitiveColorHandler(PropertyColorCustomProperty.Name, 
				FInternationalization::ForUseOnlyByLocMacroAndGraphNodeTextLiterals_CreateText(*PropertyColorCustomProperty.Text, TEXT("PropertyColor"), *PropertyColorCustomProperty.Name.ToString()),
				[this, PropertyColorCustomProperty](const UPrimitiveComponent* InPrimitiveComponent)
				{
					if (AActor* Actor = InPrimitiveComponent->GetOwner())

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/EditorObject.cpp:689

Scope (from outer to inner):

file
function     static const TCHAR* ImportProperties

Source code excerpt:

			}
		}
		else if( FParse::Command(&Str,TEXT("CustomProperties")))
		{
			check(SubobjectOuter);

			SubobjectOuter->ImportCustomProperties(Str, Warn);
		}
		else if (IsEndOfProperties(Str, Depth))

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/EditorObject.cpp:1430

Scope (from outer to inner):

file
namespace    EditorUtilities
function     static const TCHAR* ImportPropertiesStep

Source code excerpt:

				}
			}
			else if( FParse::Command(&Str,TEXT("CustomProperties")))
			{
				check(SubobjectOuter);

				SubobjectOuter->ImportCustomProperties(Str, Warn);
			}
			else if (IsEndOfProperties(Str, Depth))

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/PropertyColorSettings.h:44

Scope (from outer to inner):

file
class        class UPropertyColorSettings : public UObject

Source code excerpt:


	UPROPERTY(Config)
	TArray<FPropertyColorCustomProperty> CustomProperties;
};

#Loc: <Workspace>/Engine/Source/Runtime/CoreUObject/Private/UObject/Obj.cpp:1770

Scope (from outer to inner):

file
function     void UObject::DeclareCustomVersions

Source code excerpt:

				if (ScriptStruct)
				{
					// Construct an instance and collect CustomProperties from it via Serialize
					int32 Size = ScriptStruct->GetPropertiesSize();
					int32 Alignment = ScriptStruct->GetMinAlignment();
					AllocationBuffer.SetNumUninitialized(Align(Size, Alignment) + Alignment);
					uint8* StructBytes = Align(AllocationBuffer.GetData(), Alignment);
					ScriptStruct->InitializeStruct(StructBytes);
					ScriptStruct->SerializeItem(Ar, StructBytes, nullptr);

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Iris/Core/Private/Iris/ReplicationState/ReplicationStateDescriptorBuilder.cpp:2628

Scope (from outer to inner):

file
namespace    UE::Net
function     SIZE_T FReplicationStateDescriptorBuilder::CreateDescriptorsForClass

Source code excerpt:


	// We add separate descriptors properties with custom replication fragments
	TArray<FPropertyReplicationStateDescriptorBuilder::FMemberProperty, TInlineAllocator<8>> CustomProperties;

	FPropertyReplicationStateDescriptorBuilder::FIsSupportedPropertyParams IsSupportedPropertyParams;
	IsSupportedPropertyParams.LifeTimeProperties = &LifeTimeProperties;
	IsSupportedPropertyParams.InObjectClass = InObjectClass;
	IsSupportedPropertyParams.bAllowFastArrayWithExtraReplicatedProperties = Parameters.AllowFastArrayWithExtraReplicatedProperties;

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Iris/Core/Private/Iris/ReplicationState/ReplicationStateDescriptorBuilder.cpp:2666

Scope (from outer to inner):

file
namespace    UE::Net
function     SIZE_T FReplicationStateDescriptorBuilder::CreateDescriptorsForClass

Source code excerpt:

				{
					// We build separate descriptors for all properties with CustomReplicationFragments					
					CustomProperties.Add(MemberProperty);
					continue;
				}
				else if (EnumHasAnyFlags(MemberProperty.Traits, EMemberPropertyTraits::IsFastArray))
				{
					// FastArrayProperties should use a custom replication fragment
					UE_LOG(LogIris, Error, TEXT("FReplicationStateDescriptorBuilder::CreateDescriptorsForClass FFastArray property %s not registered and won't be replicated."), *Property->GetFullName());

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Iris/Core/Private/Iris/ReplicationState/ReplicationStateDescriptorBuilder.cpp:2792

Scope (from outer to inner):

file
namespace    UE::Net
function     SIZE_T FReplicationStateDescriptorBuilder::CreateDescriptorsForClass

Source code excerpt:

	// If we have properties with a CreateAndRegisterReplicationFragmentFunction, we build separate descriptors for them
	// We may have to re-order custom properties if there are more than one.
	if (CustomProperties.Num() > 1)
	{
		InitCVarReplicateCustomDeltaPropertiesInRepIndexOrder();

		// If CVarReplicateCustomDeltaPropertiesInRepIndexOrder is false then we use the GetLifetimeReplicatedPropsOrder instead, which is the RepLayout legacy behavior.
		if (CVarReplicateCustomDeltaPropertiesInRepIndexOrder != nullptr && !CVarReplicateCustomDeltaPropertiesInRepIndexOrder->GetBool())
		{
			TArray<FPropertyReplicationStateDescriptorBuilder::FMemberProperty, TInlineAllocator<8>> NewCustomProperties;
			NewCustomProperties.Reserve(CustomProperties.Num());
			for (const FLifetimeProperty& LifetimeProperty : LifeTimePropertiesOriginalOrder)
			{
				if (const FPropertyReplicationStateDescriptorBuilder::FMemberProperty* MemberProperty = CustomProperties.FindByPredicate([RepIndex = LifetimeProperty.RepIndex](const FPropertyReplicationStateDescriptorBuilder::FMemberProperty& MemberProperty) { return RepIndex == MemberProperty.Property->RepIndex; }))
				{
					NewCustomProperties.Add(*MemberProperty);
				}
			}

			CustomProperties = NewCustomProperties;
		}
	}

	for (uint32 CustomPropertyIt = 0, CustomArrayPropertyEndIt = CustomProperties.Num(); CustomPropertyIt != CustomArrayPropertyEndIt; ++CustomPropertyIt)
	{
		const FPropertyReplicationStateDescriptorBuilder::FMemberProperty& MemberProperty = CustomProperties[CustomPropertyIt];

		// Verify some assumptions, for now we do not support putting properties with custom replication fragments in multiple states
		check(!EnumHasAllFlags(MemberProperty.Traits, EMemberPropertyTraits::InitOnly | EMemberPropertyTraits::HasLifetimeConditionals));

		FPropertyReplicationStateDescriptorBuilder Builder;		
		FPropertyReplicationStateDescriptorBuilder::FBuildParameters BuildParameters = {};

#Loc: <Workspace>/Engine/Source/Runtime/MovieScene/Public/EntitySystem/MovieScenePartialProperties.h:55

Scope (from outer to inner):

file
namespace    UE
namespace    MovieScene
function     explicit TSetPartialPropertyValuesImpl

Source code excerpt:


	explicit TSetPartialPropertyValuesImpl(ICustomPropertyRegistration* InCustomProperties, TArrayView<const FPropertyCompositeDefinition> InCompositeDefinitions)
		: CustomProperties(InCustomProperties)
		, CompositeDefinitions(InCompositeDefinitions)
	{
		if (CustomProperties)
		{
			CustomAccessors = CustomProperties->GetAccessors();
		}
	}

	void ForEachAllocation(const FEntityAllocation* Allocation, TRead<UObject*> BoundObjectComponents, FThreeWayAccessor PropertyBindingComponents, TRead<MetaDataTypes>... InMetaData, TReadOptional<CompositeTypes>... InCompositeComponents) const;
	void ForEachAllocation(const FEntityAllocation* Allocation, TRead<UObject*> BoundObjectComponents, FTwoWayAccessor PropertyBindingComponents, TRead<MetaDataTypes>... InMetaData, TReadOptional<CompositeTypes>... InCompositeComponents) const;

#Loc: <Workspace>/Engine/Source/Runtime/MovieScene/Public/EntitySystem/MovieScenePartialProperties.h:77

Scope (from outer to inner):

file
namespace    UE
namespace    MovieScene

Source code excerpt:

private:

	ICustomPropertyRegistration* CustomProperties;
	FCustomAccessorView CustomAccessors;
	TArrayView<const FPropertyCompositeDefinition> CompositeDefinitions;
};

template<typename PropertyTraits, typename ...CompositeTypes>
using TSetPartialPropertyValues = TSetPartialPropertyValuesImpl<PropertyTraits, typename PropertyTraits::MetaDataType, TMakeIntegerSequence<int, sizeof...(CompositeTypes)>, CompositeTypes...>;

#Loc: <Workspace>/Engine/Source/Runtime/MovieScene/Public/EntitySystem/MovieScenePropertySystemTypes.h:324

Scope (from outer to inner):

file
namespace    UE
namespace    MovieScene
function     explicit TSetPropertyValuesImpl

Source code excerpt:


	explicit TSetPropertyValuesImpl(ICustomPropertyRegistration* InCustomProperties)
		: CustomProperties(InCustomProperties)
	{
		if (CustomProperties)
		{
			CustomAccessors = CustomProperties->GetAccessors();
		}
	}

	/**
	 * Task callback that applies a value to an object property via a custom native setter function
	 * Must be invoked with a task builder with the specified parameters:

#Loc: <Workspace>/Engine/Source/Runtime/MovieScene/Public/EntitySystem/MovieScenePropertySystemTypes.h:401

Scope (from outer to inner):

file
namespace    UE
namespace    MovieScene

Source code excerpt:

private:

	ICustomPropertyRegistration* CustomProperties;
	FCustomAccessorView CustomAccessors;
};


/**
 * Stateless entity task that will apply values to properties. Three types of property are supported: Custom native accessor functions, fast pointer offset, or FTrackInstancePropertyBindings

#Loc: <Workspace>/Engine/Source/Runtime/MovieScene/Public/EntitySystem/MovieScenePropertySystemTypes.h:456

Scope (from outer to inner):

file
namespace    UE
namespace    MovieScene
function     explicit TGetPropertyValuesImpl

Source code excerpt:


	explicit TGetPropertyValuesImpl(ICustomPropertyRegistration* InCustomProperties)
		: CustomProperties(InCustomProperties)
	{
		if (CustomProperties)
		{
			CustomAccessors = CustomProperties->GetAccessors();
		}
	}

	/**
	 * Task callback that retrieves the object's current value via a custom native setter function, and writes it to the specified output variable
	 * Must be invoked with a task builder with the specified parameters:

#Loc: <Workspace>/Engine/Source/Runtime/MovieScene/Public/EntitySystem/MovieScenePropertySystemTypes.h:537

Scope (from outer to inner):

file
namespace    UE
namespace    MovieScene

Source code excerpt:

private:

	ICustomPropertyRegistration* CustomProperties;
	FCustomAccessorView CustomAccessors;
};


template<typename PropertyTraits>
struct TGetPropertyValues : TGetPropertyValuesImpl<PropertyTraits, typename PropertyTraits::MetaDataType>

#Loc: <Workspace>/Engine/Source/Runtime/MovieScene/Public/EntitySystem/MovieScenePropertySystemTypes.h:591

Scope (from outer to inner):

file
namespace    UE
namespace    MovieScene
function     explicit TSetCompositePropertyValuesImpl

Source code excerpt:


	explicit TSetCompositePropertyValuesImpl(ICustomPropertyRegistration* InCustomProperties)
		: CustomProperties(InCustomProperties)
	{
		if (CustomProperties)
		{
			CustomAccessors = CustomProperties->GetAccessors();
		}
	}

	/**
	 * Task callback that applies a value to an object property via a custom native setter function
	 * Must be invoked with a task builder with the specified parameters:

#Loc: <Workspace>/Engine/Source/Runtime/MovieScene/Public/EntitySystem/MovieScenePropertySystemTypes.h:680

Scope (from outer to inner):

file
namespace    UE
namespace    MovieScene

Source code excerpt:

private:

	ICustomPropertyRegistration* CustomProperties;
	FCustomAccessorView CustomAccessors;
};

template<typename PropertyTraits, typename ...CompositeTypes>
using TSetCompositePropertyValues = TSetCompositePropertyValuesImpl<PropertyTraits, typename PropertyTraits::MetaDataType, CompositeTypes...>;