Python Query MovieSceneFloatSection Returns Empty Channel Name

When you have a custom float channel and run the above, It works great if it’s a regular ‘MovieScene3DTransformSection’ :

LogPython: [{channel_name: “Location.Y”, section: “/Script/MovieSceneTracks.MovieScene3DTransformSection’/Game/NewLevelSequence.NewLevelSequence:MovieScene_0.MovieScene3DTransformTrack_3.MovieScene3DTransformSection_0’”}]

But if you have float keys selected, the channel name is empty:

LogPython: [{channel_name: “”, section: “/Script/MovieSceneTracks.MovieSceneFloatSection’/Game/NewLevelSequence.NewLevelSequence:MovieScene_0.MovieSceneFloatTrack_1.MovieSceneFloatSection_0’”}]

This can cause issues down the line with .get_name() , but it’s proving particularly difficult to cast to as an unreal.SequencerChannelProxy"in order to satisfy unreal.SequencerCurveEditorObject

.select_keys() which is what I’m ultimately hoping to do.

Could be pilot error on my part but I’m sorta going in circles so any help appreciated :slight_smile:

Casey

Steps to Reproduce
This is running on a vanilla 5.7 install on Windows 11. No custom plugins or fancy settings…

{Assuming you have selected the keys of a custom float curve in the curve editor…}

level_seq_subsystem = unreal.get_editor_subsystem(unreal.LevelSequenceEditorSubsystem)

curve_editor = level_seq_subsystem.get_curve_editor()

keyed_channels = curve_editor.get_channels_with_selected_keys()

print(keyed_channels[0])

Hey there,

Yes, there is a bug here where the interface that collects information about the curve is fetching metadata for custom properties that is empty and we don’t currently fix it up. I’ve logged an issue here: https://issues.unrealengine.com/issue/UE-355265

Unfortunately, there isn’t workaround python that I would offer. Instead I could recommend a modification to the engine. In IKeyArea::CreateCurveEditorModel, you could do something like:

if (MetaData->Name.IsNone())
{
	CurveModel->SetChannelName(DisplayText);
}

Note, though, that the metadata model exists because we have different types of display names versus other names.

Another, deeper option would be to explore why the metadata for a custom curve is not being populated with the correct name. However, that would be the intent on our side with the bug.

Dustin

Hi there Dustin thank you for the response and logging the bug :blush:

I’ll investigate the above (though admittedly I haven’t done much C++ yet)

It seems that most of the Python exposing is geared towards MovieScene3DTransformSection which is sensible since that’s the most commonly used, but I think many ex-Maya folks like myself will want to mimic the ease of creating a custom attribute and pythonically keying it like any other attr. I’ve mostly got this working but occasionally hit a wall on something seemingly simple…

For example:

Having selected some keys in the curve editor, what’s the cleanest way to fetch the Actor that these keys are driving? Using .outer() moves you from section to track, which is cool, but then continues it’s orbit to the level sequence object. It seems you can only get bindings from ‘the top’ ie: get_current_level_sequence() and work your way downwards as opposed to being able to query what a given channel/track is bound by and climb the connection hierarchy upwards. This is fine for smaller scenes, but might get slow on heavier scenes.

In the short term would you be so kind as to provide a working example of unreal.SequencerCurveEditorObject.select_keys()

I keep getting errors that the channel can’t be cast as a

unreal.SequencerChannelProxy()

even though it very much is a channel !

Another aspect of this (sorry for the rant) is that the channel.get_names() dynamically append an underscore and an integer as if they are indexes. This makes is tough to utilize

if track.get_display_name() == ‘your curve’ during the search.

Thanks again!

Casey

[Image Removed]

Yep understood,

“but I think many ex-Maya folks like myself will want to mimic the ease of creating a custom attribute and pythonically keying it like any other attr”

I’ll make a really general statement and then a qualifier. Whenever I’ve found myself fighting something in Unreal, I typically ask a question which is, “how do they want me to access/do/create this?” and that sometimes get’s me in and looking at engine code to figure out it’s use cases. The qualifier is that sometimes we get it wrong or there is a bug. We’ve heard quite a bit of this feedback over the years and so there are some efforts going on to make the python API better in the future (more pythonic).

I keep getting errors that the channel can’t be cast as a unreal.SequencerChannelProxy()

Yeah, this is a tough problem because you really need to be able to drill down into the sequence to get to the level you want and because of the first issue, there are other problems.

import unreal
seq = unreal.LevelSequenceEditorBlueprintLibrary.get_current_level_sequence()
 
# Get the MovieScene
movie_scene = unreal.MovieSceneSequenceExtensions.get_movie_scene(seq)
 
all_bindings = unreal.MovieSceneSequenceExtensions.get_bindings(seq)
for binding in all_bindings:
    # Find a specific track type bound to an object/property (e.g., UMovieSceneFloatTrack)
    all_tracks = binding.get_tracks()
   
    # Iterate tracks and sections to find the one you want, you can shortcut this if you use the get_selected_tracks() function in MovieSceneTrackExtensions
    for track in all_tracks:
        if(type(track) == unreal.MovieSceneDoubleTrack):
            sections = unreal.MovieSceneTrackExtensions.get_sections(track)
            for section in sections:
                # Build a specific channel by name, "None" in this case because of the meta data problem I mentioned before...
                chan = unreal.SequencerChannelProxy(channel_name="None", section=section)
                if chan:
                    # Then select the key, with the primary issue being that you need to have the channel selected in the curve editor to do so ahead of time...
                    level_seq_subsystem = unreal.get_editor_subsystem(unreal.LevelSequenceEditorSubsystem)
                    curve_editor = level_seq_subsystem.get_curve_editor()
                    curve_editor.select_keys(chan, [1])

Another aspect of this (sorry for the rant) is that the channel.get_names() dynamically append an underscore and an integer as if they are indices.

Yes, one of the problems here is that in some cases you can have multiple sections on a single track, and these numbers are appended to track channels as a part of the unique identification. Right now, the extensions we’ve built for scripting try to handle it usually through selection, as I mentioned in the shortcut script above. I’ll raise this issue tomorrow with the dev team.

Dustin

You rock dude that worked !!

>>The qualifier is that sometimes we get it wrong or there is a bug…

All good, no criticisms here ! For every 1 issue, there are 10 other things that I’m amazed by in UE :+1:

>>I’ll raise this issue tomorrow with the dev team

That would be great thanks ! One other thing while we’re in this headspace and you’re chatting with the devs tomorrow, is that we need the ability to query a curve at a given time, whether or not there’s a key there. So far it’s seeming like you can only query a curve value at a given time if there’s an actual key there. But if there’s a key on frame 1 and on frame 100 I don’t believe there’s a way to ask what the value of the curve at frame 50 is…

Not sure if it will upload but I’ve attached a video of the script in action. You’ll see why I was trying to get the behavior of reselecting the float curve keys since by default they seemed to get deselected unlike the transform tracks…

Thanks again !

Casey

Looks great, thanks for sharing!

Happy to have helped.