Opportunity to change variables in Blueprint assets

Hello Team,

I’m reaching out to ask for advice regarding a Utility Blueprint task. I’m trying to change a specific property across multiple Blueprint assets. Specifically, I need to go through a number of Blueprints, filter for a certain component, and set a bool property on that component.

Specifically, I can successfully access native or inherited components (like RootComponent, StaticMeshComponent, etc.) by inspecting the Class Default Object (CDO) using get_default_object (generated_class)

However, I am unable to access components that were manually added via the Blueprint Editor’s Components panel if they are inherited from a parent Blueprint.

I haven’t found a clean or efficient way to do this yet. Could you please advise on the best approach?

Best regards,

Levan

Hi Levan,

Sorry about the delay. I am looking into this now and should get back to you soon.

Best regards,

Vitor

Hi Levan,

The recommended way to access blueprint components and script operations on them is to use the API provided by the SubobjectDataSubsystem and the SubobjectDataBlueprintFunctionLibrary. From your usage of “get_default_object(generated_class)”, I assume you are working with Python:

subobject_subsystem = unreal.get_engine_subsystem(unreal.SubobjectDataSubsystem)When using the SubobjectDataSubsystem, you can work directly with blueprint assets or actor instances, no need to access their generated class or default objects. Simply iterate over the components using one of these functions:

subhandles = subobject_subsystem.k2_gather_subobject_data_for_instance(actor) subhandles = subobject_subsystem.k2_gather_subobject_data_for_blueprint(blueprint)The returned array will have a handle for the generated class as its first item, and the components following next, including native and blueprint, locally-defined or inherited. For example, here is a function to print some information about selected blueprint assets and all of their subobjects:

`def print_selected_blueprint_subobjects_info():

subobject_subsystem = unreal.get_engine_subsystem(unreal.SubobjectDataSubsystem)

selected_assets = unreal.EditorUtilityLibrary.get_selected_assets()
for asset in selected_assets:
blueprint = unreal.BlueprintEditorLibrary.get_blueprint_asset(asset)
if unreal.SystemLibrary.is_valid(blueprint):
unreal.log(“Class: "” + blueprint.get_name() + “" Name: "” + asset.get_name() + “" Path: "” + asset.get_path_name() + “"”)
subhandles = subobject_subsystem.k2_gather_subobject_data_for_blueprint(blueprint)
for subhandle in subhandles:
subdata = unreal.SubobjectDataBlueprintFunctionLibrary.get_data(subhandle)
component = unreal.SubobjectDataBlueprintFunctionLibrary.get_object_for_blueprint(subdata, blueprint)
component_name = unreal.SubobjectDataBlueprintFunctionLibrary.get_variable_name(subdata)
unreal.log(“Component: "” + component.get_class().get_name() + “" Name: "” + component_name.str() + “"”)

unreal.log(“”)`Once you have a handle to a subobject, you can use the SubobjectDataBlueprintFunctionLibrary to get its internal SubobjectData:

subdata = unreal.SubobjectDataBlueprintFunctionLibrary.get_data(subhandle)From there, you can query information about the subobject. Some examples:

unreal.SubobjectDataBlueprintFunctionLibrary.is_component(subdata) unreal.SubobjectDataBlueprintFunctionLibrary.is_root_component(subdata) unreal.SubobjectDataBlueprintFunctionLibrary.is_scene_component(subdata) unreal.SubobjectDataBlueprintFunctionLibrary.is_native_component(subdata) unreal.SubobjectDataBlueprintFunctionLibrary.is_inherited_component(subdata) unreal.SubobjectDataBlueprintFunctionLibrary.get_variable_name(subdata)You can also access the component’s object and set variables on it directly:

`# Get the component in the blueprint where it was defined
component = unreal.SubobjectDataBlueprintFunctionLibrary.get_object(subdata)

Get the component in the “blueprint” object, where inherited components can override variables from their parent

component = unreal.SubobjectDataBlueprintFunctionLibrary.get_object_for_blueprint(subdata, blueprint)

if component.get_class().get_name() == “StaticMeshComponent”:
static_mesh = unreal.StaticMeshComponent.cast(component)
static_mesh.set_editor_property(“visible”, True)`Note that there are two functions to get the component object. Consider you have a hierarchy like the following:

`- BPActor1 containing BPComponent1

  • BPActor2 containing BPComponent2
  • BPActor3 containing BPComponent3`In that hierarchy, BPActor3 defines BPComponent3 and inherits all the components from their ancestors. Here are some example gets:

`get_object(BPComponent1Data) → returns BPComponent1 on BPActor1
get_object(BPComponent2Data) → returns BPComponent2 on BPActor2
get_object(BPComponent3Data) → returns BPComponent3 on BPActor3

get_object_for_blueprint(BPComponent1Data, BPActor1) → returns BPComponent1 on BPActor1
get_object_for_blueprint(BPComponent1Data, BPActor2) → returns BPComponent1’s override on BPActor2
get_object_for_blueprint(BPComponent1Data, BPActor3) → returns BPComponent1’s override on BPActor3
get_object_for_blueprint(BPComponent2Data, BPActor2) → returns BPComponent2 on BPActor2
get_object_for_blueprint(BPComponent2Data, BPActor3) → returns BPComponent2’s override on BPActor3
get_object_for_blueprint(BPComponent3Data, BPActor3) → returns BPComponent3 on BPActor3`I hope this is helpful. Please let me know if this solution works for you, or if you still need any further assistance.

Best regards,

Vitor

Hello Vitor,

Thank you for the solution you provided earlier. However, I decided to take a different approach to the issue.

Instead of following your method, I added the function to the

BzEditorFunctionLibrary

and call it from my utility Blueprint.

Here’s the function I implemented:

`UActorComponent* UBzEditorFunctionLibrary::GetBlueprintComponentTemplate(UBlueprint* Blueprint, FName ComponentVarName)
{
if (!Blueprint)
{
return nullptr;
}

UClass* TargetClass = Blueprint->GeneratedClass;
if (!TargetClass)
{
return nullptr;
}

UBlueprintGeneratedClass* RootBPClass = Cast(TargetClass);
UClass* SearchClass = TargetClass;

while (SearchClass && SearchClass != AActor::StaticClass())
{
UBlueprintGeneratedClass* BPClass = Cast(SearchClass);
if (BPClass && BPClass->SimpleConstructionScript)
{
const TArray<USCS_Node*>& Nodes = BPClass->SimpleConstructionScript->GetAllNodes();
for (USCS_Node* Node : Nodes)
{
if (!Node)
continue;

FName NodeVarName = Node->GetVariableName();
if (NodeVarName == ComponentVarName)
{
UActorComponent* TemplateComp = Node->GetActualComponentTemplate(RootBPClass);
return TemplateComp;
}
}
}
SearchClass = SearchClass->GetSuperClass();
}

return nullptr;
}`

This function takes two inputs: a UBlueprint and a component variable name. It searches for the component by name within the Blueprint and returns the corresponding template component. You can then cast the output to the appropriate component class and access its properties as needed.

Thank you again for your help—no further assistance is required at this point.

Best regards,

Levan Surmanidze

By the way, I just noticed this: UE-196994. According to it, get_object_for_blueprint() might not be working correctly in UE 5.3 (the fix was made for 5.4). The CL mentioned does not seem to be accessible, but I believe it is probably the same as 29968056 (SHA-1 31c63dde5358e3fe419c9b71108d17403a33ca11 on GitHub), so you can probably cherry-pick the fix if you are working with a source build.

Hi Levan,

Thank you for providing your solution, this can be very helpful for other developers who come searching for information about this topic.

Best regards,

Vitor