How can I resolve an ExposedReference from within a Marker?

Hello, I’m trying to figure out how to resolve an ExposedReference from within a Marker.

I’ve seen in several places how to do it for a PlayableAsset (a clip?):

public ExposedReference<Transform> exposedTransform;
     
        public override Playable CreatePlayable(PlayableGraph graph, GameObject owner)
        {
            var playable = ScriptPlayable<AddBloodBehaviour>.Create(graph);
            actualTransform = exposedTransform.Resolve(graph.GetResolver());
            return playable;
        }

How could I resolve this exposedTransform if I was using a Marker? I don’t know how to access the ‘graph’ from the Marker itself. I see that it has “parent” which is the TrackAsset, and the “timelineAsset” from there, but I’m not sure if there is a way to get to the “graph” from there so I can use graph.GetResolver().

And just to clarify, I know how to set up the INotificationReceiver and resolve the ExposedReference on that. I just don’t know how to do it on the Marker itself.

My end goal is to be able to add an ExposedReference to a Marker, and then also display the inspector for MySpecialComponent so that I can modify it while I have the Marker selected. Is this possible?

Thanks for any help!

To resolve an exposed reference from an Editor (inspector) class, you can cast the Selection’s active context as a PlayableDirector. When a Timeline clip/marker is selected, Timeline automatically puts the PlayableDirector as a context object. This will let you resolve the exposed reference in your Marker object.

public class TestMarker : Marker
{
    public ExposedReference<Light> light;
}

[CustomEditor(typeof(TestMarker))]
public class TestMarkerInspector : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        //when a Timeline clip/marker is selected, the director is added as a context object
        var directorContext = Selection.activeContext as PlayableDirector;
        var inspectedMarker = target as TestMarker;

        if (directorContext != null && inspectedMarker != null)
        {
            PropertyName referenceExposedName = inspectedMarker.light.exposedName;
            Light lightReference = directorContext.GetReferenceValue(referenceExposedName, out bool isValid) as Light;

            if (isValid && lightReference != null)
            {
                Editor inspector = CreateEditor(lightReference);
                inspector.OnInspectorGUI();
            }
        }
    }
}

Now I can display the Light’s inspector embedded in the custom Marker inspector:6762904--781006--upload_2021-1-25_10-26-26.png

2 Likes

@julienb Thank you, this worked perfectly. This was the last thing I needed to figure out for my Timeline implementation (knock on wood), so I seriously appreciate the explanation and the example!

1 Like

@julienb I tried your suggestion in 2021.1 and 2021.2 but my Selection.activeContexis always null. I’m currently trying this for a custom inspector for a timeline clip (not a marker as in your example) but you mentioned that it would work for clips (ITimelineClipAsset) as well, right?

Is this documented somewhere or do you know a different way to resolve exposed references? My current workaround is to set properties during CreatePlayable where I have access to the graph but this happens after
ClipEditor::OnClipChanged and it’s not very stable.

I’m trying to set the duration of a clip based on an exposed reference.

@Jamez0r Is this approach still working for you?

I just tried it with a CustomMarker and it works. Just can’t get it working for clips :confused:

Okay, finally found it. UnityEditor.Timeline.TimelineEditor.inspectedDirector

Class TimelineEditor | Timeline | 1.6.3 (unity3d.com)

From there you can get the graph and resolver via TimelineEditor.inspectedDirector.playableGraph.GetResolver().

Took me two days to find but now that I know it exists it all makes sense :slight_smile:

1 Like

Correct me if I’m wrong but isn’t this true?

TimelineEditor.inspectedDirector == TimelineEditor.inspectedDirector.playableGraph.GetResolver()