Iterating over array of static mesh components corrupts the array

Hi, I’m working on writing several production helper python scripts, and currently writing one that iterates over all the static mesh components of all your selected actors in the level. For each actor/static mesh component, it sets Visible to Off, and Affect Indirect Lighting While Hidden to On.

The issue I’m running into is that it will successfully do this for the first one or two static mesh components in the array, but after that point the array gets corrupted and tries to run on non-existing components.

I had originally started this script with a much higher scope, ie, storing these values as Level Variant Sets, but after running into this problem, lowered the scope of the script to try to narrow down the issue.

Here is the simplified script:

import unreal

def Visible_Off_Indirect_On():
    # Get currently selected actors
    selected_actors = unreal.EditorLevelLibrary.get_selected_level_actors()

    # Loop over all selected actors
    for actor in selected_actors:
        # Find all StaticMeshComponents in the actor
        components = actor.get_components_by_class(unreal.StaticMeshComponent)

        for component in components:
            print(component)
            component.set_editor_property('visible', False)
            component.set_editor_property('affect_indirect_lighting_while_hidden', True)

# Run the function
Visible_Off_Indirect_On()

If I comment out the part of the function that actually sets the properties, the print function prints all the correct static mesh components. If I leave the set_editor_property active, it will work correctly for the first component, but when it prints the 2nd component, the name it prints is something completely different.

Here is an example of what is printed when the set_editor_property is commented out:
[2024.10.09-09.21.38:038][915]LogPython: <Object ‘/Game/Levels/Main.Main:PersistentLevel.BP_KB3D_AMC_BldgLgArcade_A_grp_C_0.SM_KB3D_AMC_BldgLgArcade_A_PayPhone’ (0x00000661B6A14800) Class ‘StaticMeshComponent’>
[2024.10.09-09.21.38:044][915]LogPython: <Object ‘/Game/Levels/Main.Main:PersistentLevel.BP_KB3D_AMC_BldgLgArcade_A_grp_C_0.SM_KB3D_AMC_BldgLgArcade_A_CanopyB’ (0x00000661B6A15000) Class ‘StaticMeshComponent’>
[2024.10.09-09.21.38:055][915]LogPython: <Object ‘/Game/Levels/Main.Main:PersistentLevel.BP_KB3D_AMC_BldgLgArcade_A_grp_C_0.SM_KB3D_AMC_BldgLgArcade_A_CanopyC’ (0x00000661B6A15800) Class ‘StaticMeshComponent’>
[2024.10.09-09.21.38:066][915]LogPython: <Object ‘/Game/Levels/Main.Main:PersistentLevel.BP_KB3D_AMC_BldgLgArcade_A_grp_C_0.SM_KB3D_AMC_BldgLgArcade_A_CanopyD’ (0x00000661B6A16000) Class ‘StaticMeshComponent’>
[2024.10.09-09.21.38:077][915]LogPython: <Object ‘/Game/Levels/Main.Main:PersistentLevel.BP_KB3D_AMC_BldgLgArcade_A_grp_C_0.SM_KB3D_AMC_BldgLgArcade_A_CanopyE’ (0x00000661B6A16800) Class ‘StaticMeshComponent’>
[2024.10.09-09.21.38:088][915]LogPython: <Object ‘/Game/Levels/Main.Main:PersistentLevel.BP_KB3D_AMC_BldgLgArcade_A_grp_C_0.SM_KB3D_AMC_BldgLgArcade_A_CanopyF’ (0x00000661B6A17000) Class ‘StaticMeshComponent’>
[2024.10.09-09.21.38:099][915]LogPython: <Object ‘/Game/Levels/Main.Main:PersistentLevel.BP_KB3D_AMC_BldgLgArcade_A_grp_C_0.SM_KB3D_AMC_BldgLgArcade_A_CanopyG’ (0x00000661B6A17800) Class ‘StaticMeshComponent’>
[2024.10.09-09.21.38:110][915]LogPython: <Object ‘/Game/Levels/Main.Main:PersistentLevel.BP_KB3D_AMC_BldgLgArcade_A_grp_C_0.SM_KB3D_AMC_BldgLgArcade_A_CanopyA’ (0x00000661B6A18000) Class ‘StaticMeshComponent’>

And here is the result when the set_editor_property is triggered:
[2024.10.09-09.22.16:943][713]LogPython: <Object ‘/Game/Levels/Main.Main:PersistentLevel.BP_KB3D_AMC_BldgLgArcade_A_grp_C_0.SM_KB3D_AMC_BldgLgArcade_A_PayPhone’ (0x00000661B6A14800) Class ‘StaticMeshComponent’>
[2024.10.09-09.22.16:975][713]LogPython: <Object ‘/Game/Levels/Main.Main:PersistentLevel.BP_KB3D_AMC_BldgLgArcade_A_grp_C_0.TRASH_StaticMeshComponent_48’ (0x00000661B6A15000) Class ‘StaticMeshComponent’>
[2024.10.09-09.22.16:984][713]LogPython: <Object ‘/Game/Levels/Main.Main:PersistentLevel.BP_KB3D_AMC_BldgLgArcade_A_grp_C_0.TRASH_StaticMeshComponent_49’ (0x00000661B6A15800) Class ‘StaticMeshComponent’>
[2024.10.09-09.22.16:995][713]LogPython: <Object ‘/Game/Levels/Main.Main:PersistentLevel.BP_KB3D_AMC_BldgLgArcade_A_grp_C_0.TRASH_StaticMeshComponent_50’ (0x00000661B6A16000) Class ‘StaticMeshComponent’>
[2024.10.09-09.22.17:006][713]LogPython: <Object ‘/Game/Levels/Main.Main:PersistentLevel.BP_KB3D_AMC_BldgLgArcade_A_grp_C_0.TRASH_StaticMeshComponent_51’ (0x00000661B6A16800) Class ‘StaticMeshComponent’>

Any idea what the heck Unreal is doing here? How is my array getting corrupted, where are these TRASH_StaticMeshComponents coming from??

which set editor property is causing this? one of them or either of those?

Also, you have two loops.

Commenting out either of the set editor properties causes the same effect. Commenting out them both causes the array to be printed correctly.

Yes, the two loops are intentional. The first is to iterate through all selected actors, the second is to iterate through each actor’s static mesh components.

Maybe clearing the components array after the second loop. Also, do you check if the component is a static mesh.

Where is component defined. Don’t see anything. Is it from the actor?

The components array is already a list of static mesh components, as that is the specific object type the array finds on each actor.

component is an item within the components array, which is defined with

components = actor.get_components_by_class(unreal.StaticMeshComponent)

Seems like clearing the array after the second loop would break the for loop for setting the properties. It would only set the properties on the first component and then stop.

Make sure its after the loop, not within the loop.

try to read (get) visibility property and print it.

I worked with a colleague of mine to try a different approach to this, and we did end up getting it working. Basically changing a property on a component like that causes Unreal to reevaluate all the objects stored in memory (or so we think?). By moving away from the object-oriented approach, and instead rebuilding the list of components every time we loop over, minus ones that were already processed, we were able to get it apply the property settings to all selected actors / components / properties. Kind of a roundabout way of doing things, and it’s not very fast to process on large selections, but it does work.