How to update blueprint property through editor code

Hello,

I am trying to implement a plugin that extends the Blueprint Editor with a custom property editor. I am using the following code to update the property value on a blueprint:

TSharedPtr<FBlueprintEditor> BlueprintEditor = WeakBlueprintEditor.Pin();
if (BlueprintEditor->IsEditingSingleBlueprint())
{
    if (TSubclassOf<UObject> GeneratedClass = BlueprintEditor->GetBlueprintObj()->GeneratedClass)
    {
        if (UObject* DefaultObject = GeneratedClass->GetDefaultObject())
        {
            FStrProperty* Property = FindFProperty<FStrProperty>(GeneratedClass, "GenerationScript");
            Property->SetPropertyValue_InContainer(DefaultObject, GenerationScript);
            DefaultObject->Modify(true);
        }
    }
}

This properly updates the property value on the blueprint asset. However, this does not seem to update the values of properties of any instance blueprints in the level. (The property is marked VisibleAnywhere)

What code should I be using to modify the property on the blueprint and have the change reflect to the scene instances as well?

Thanks.

It might be required to call PreEditChange and PostEditChange on the property which are used when you modify a property from the editor panel. Other than that I’m not sure if instances in the level are supposed to update automatically as I often noticed that changes I make in Blueprint to a class are not always reflected to instances I already placed in a level.

I do know that the CoreRedirect system can work with instances, maybe that helps finding an answer. note the InstanceOnly on ClassRedirects:

Thank you for your reply. Adding PreEditChange and PostEditChange did not resolve the issue. As far as I am aware, properties of instances in the level should inherit changes from the blueprint only if they have not been modified manually in level instance.

I have made a little video to better illustrate the issue:

Assuming the following two properties in my C++ Actor class
vars

First, I toggle the boolean through the blueprint editor, and the changes reflect properly in the scene instance.

Then, I change the string content using my editor plugin. This uses the code I posted in the original post to update the property value. As you can see, the value in the level does not update when I modify the string. However, when I compile the blueprint, the level editor does detect that the instance property value is different from the blueprint, and shows the little revert button to revert to blueprint value.

I am clearly missing a piece of code to propagate the changes to the instance, but it is not clear to me by browsing Unreal’s blueprint editor code what this code is.

Additionally, it may also be possible that my plugin is editing the property on the wrong class. I referenced the property editing class from this post:

Any insights are very welcome.

I’ve found something in:

\UE_4.27\Engine\Source\Editor\UnrealEd\Private\Editor.cpp

int32 CopyActorProperties( AActor* SourceActor, AActor* TargetActor, const FCopyOptions& Options )

This method collects archetype instances, which if I’m correct are modified instances in the level, before copying data. It’s a big method.

TArray<AActor*> ArchetypeInstances;
if( Options.Flags & ECopyOptions::PropagateChangesToArchetypeInstances )
{
	TArray<UObject*> ObjectArchetypeInstances;
	TargetActor->GetArchetypeInstances(ObjectArchetypeInstances);

	for (UObject* ObjectArchetype : ObjectArchetypeInstances)
	{
		if (AActor* ActorArchetype = Cast<AActor>(ObjectArchetype))
		{
			ArchetypeInstances.Add(ActorArchetype);
		}
	}
}

Editor panels often show a preview object, might not be directly editing the CDO.

I managed to implement a solution that worked for me using that piece of code, thank you.

I am not sure if this is the way Unreal propagates property changes to instances internally, but it works for my particular case.

I added the following code after the property assignment:

TArray<UObject*> ObjectArchetypeInstances;
DefaultObject->GetArchetypeInstances(ObjectArchetypeInstances);

for (int32 i = 0; i < ObjectArchetypeInstances.Num(); i++)
{
    Property->SetPropertyValue_InContainer(BuildingInstance, GenerationScript);
}
1 Like