How to propagate plugin settings to created objects?

Working on a custom plugin that defines a new actor component and looking to implement global settings to control the initial values of newly created objects.

The main question is how to connect the settings with the component?



UCLASS(Config=Editor, DefaultConfig, meta=(DisplayName="MyPlugin"))
class MYPLUGIN_API UMyPluginSettings : public UDeveloperSettings

Whenever the settings variables are changed, we can update the component’s class default object (CDO)

UMyPluginComponent* CDO = GetMutableDefault<UMyPluginComponent>();
const UMyPluginSettings* Settings = GetDefault<UMyPluginSettings>();

if (!CDO || !Settings)
{
	return;
}

CDO->Property = Settings->Property;
...

This works to some degree as the details panel shows the reset arrow next to properties that do not match the CDO. However, new components are still created with the default values from their header, not the CDO. Are objects not created using the CDO? Is there some other way that we should be initializing values set in the settings?

How can we ensure that global settings values are used whenever a new component is spawned?

It should not matter if the component is created and added using C++, BPs or the editor.

:key: Why your current approach doesn’t fully work

When you do this:

UMyPluginComponent* CDO = GetMutableDefault<UMyPluginComponent>();
CDO->Property = Settings->Property;

You are modifying the CDO at runtime (or after load). The problem is:

  • The CDO is initialized very early, during class loading.

  • Many objects (especially in editor workflows or Blueprints) may already:

    • Have been created

    • Or cached default values before your update runs

:backhand_index_pointing_right: So even though the CDO is updated, new instances may still use the original compiled defaults, especially in cases like:

  • Blueprint class defaults

  • Serialized assets

  • Editor-added components


:brain: Key concept

The CDO is not a “live global template” that always propagates changes automatically.

It’s more like:

  • A snapshot used during object construction

  • And sometimes overridden by Blueprint defaults or serialized values


:white_check_mark: Recommended Solutions

1. Apply settings during component initialization (Best approach)

Instead of relying on the CDO, explicitly apply settings when the component is created:

void UMyPluginComponent::OnRegister()
{
	Super::OnRegister();

	const UMyPluginSettings* Settings = GetDefault<UMyPluginSettings>();
	if (Settings)
	{
		Property = Settings->Property;
	}
}

Or alternatively:

void UMyPluginComponent::PostInitProperties()
{
	Super::PostInitProperties();

	if (!HasAnyFlags(RF_ClassDefaultObject))
	{
		const UMyPluginSettings* Settings = GetDefault<UMyPluginSettings>();
		if (Settings)
		{
			Property = Settings->Property;
		}
	}
}

:check_mark: This ensures:

  • Every new instance gets the latest settings

  • Works for C++, Blueprints, and editor-created components


2. Handle editor changes (optional but useful)

If you want changes in settings to propagate immediately:

#if WITH_EDITOR
void UMyPluginSettings::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
	Super::PostEditChangeProperty(PropertyChangedEvent);

	for (TObjectIterator<UMyPluginComponent> It; It; ++It)
	{
		UMyPluginComponent* Comp = *It;
		if (Comp)
		{
			Comp->Property = Property;
		}
	}
}
#endif

:check_mark: This updates existing instances in the editor


3. Avoid relying solely on CDO mutation

Updating the CDO:

  • Is not guaranteed to affect Blueprint defaults

  • Won’t override serialized values

  • Can lead to inconsistent behavior

:backhand_index_pointing_right: Think of CDO updates as editor hints, not a full propagation system.


:puzzle_piece: Final takeaway

To ensure global settings are always respected:

:check_mark: Do this:

  • Apply settings in PostInitProperties, OnRegister, or constructor logic

:cross_mark: Don’t rely on:

  • Updating the CDO at runtime as your main mechanism

:light_bulb: Simple rule

If you want consistent initialization across C++, Blueprints, and the editor — initialize from settings inside the component itself, not via the CDO.

I was really hoping for insights from someone who has implemented their own global defaults in plugin settings rather than a copy-paste from a chatbot.