DefaultPlayables: Is ExposedReference inspector broken or am misunderstanding how to set them?

I watched the entire presentation about custom playables and DefaultPlayables package from James Bouckley and wanted to give the Default Playables asset a try. The whole system is pretty understandable and simple to use - or so I thought, until I tried to use Transform Tween Track and other examples from the Default Playables package which made use of ExposedReference fields within clips. Creating a Transform Tween Track and inserting a clip onto that track greeted me with this inspector:

That inspector shows me the state of a TransformTweenClip class instance, which is organized like this internally - pretty much like the sample tween class covered in the talk:

public class TransformTweenClip : PlayableAsset, ITimelineClipAsset
{
    public TransformTweenBehaviour template = new TransformTweenBehaviour ();
    public ExposedReference<Transform> startLocation;
    public ExposedReference<Transform> endLocation;
    ...

The inspector is actually drawn from two places. Three fields on top (position, rotation, type) belong to the template container, and are are drawn by TransformTweenDrawer class - an ordinary property drawer class almost exactly replicating one covered in the talk by James.

Below, ExposedReference fields are drawn usingā€¦ no idea what (probably some internal class from UnityEditor which I wasnā€™t able to trace). And this is where I became completely stumped - these fields look wrong and donā€™t actually give me any way to fill the clip with proper scene references. Letā€™s take a closer look at the first ExposedReference field in this class.

Unfortunately, the talk never featured a single screenshot of an inspector of a clip class with an ExposedReference field in it - nor did any third-party tutorials on YouTube, so Iā€™m just guessing that the inspector renders the field wrong.

But based on my understanding of idea behind ExposedReference struct and on verbal descriptions from the presentation by James, the field should look like an ordinary reference field - a plain box you can drag scene objects into, and it should use the dragged objects to fill the PropertyName exposedName field - for later retrieval of a given object from PlayableGraph through Resolve calls. Instead, what weā€™re seeing here seems like a ā€œnakedā€, default-like inspector for ExposedReference, with the PropertyName and default reference shown directly and no decoration hiding them away. Itā€™s impossible to actually make a clip reference anything in the scene with this inspector - you can validate it yourself by adding logging after Resolve calls into the TransformTweenClip class, like this:

[Serializable]
public class TransformTweenClip : PlayableAsset, ITimelineClipAsset
{
    public TransformTweenBehaviour template = new TransformTweenBehaviour ();
    public ExposedReference<Transform> startLocation;
    public ExposedReference<Transform> endLocation;
 
    public ClipCaps clipCaps
    {
        get { return ClipCaps.Blending; }
    }

    public override Playable CreatePlayable (PlayableGraph graph, GameObject owner)
    {
        var playable = ScriptPlayable<TransformTweenBehaviour>.Create (graph, template);
        TransformTweenBehaviour clone = playable.GetBehaviour ();
        clone.startLocation = startLocation.Resolve (graph.GetResolver ());
        clone.endLocation = endLocation.Resolve (graph.GetResolver ());

        Debug.Log
        (
            "Start location ExposedReference was resolved " + (clone.startLocation == null ? "to null" : "successfully") +
            " | End location ExposedReference was resolved " + (clone.endLocation == null ? "to null" : "successfully")
        );

        return playable;
    }
}

Initially, I was wondering whether I misunderstood something and whether default value field was the right place to drag my scene objects into. But logging the resolution results and rechecking the talk confirmed to me that default value field has no effect on resolution (the logs told me the result is always null even if default value is filled) and shouldnā€™t even be shown in the inspector.

So, to summarize, here is my current understanding of the situation:

  • ExposedReference fields are never included into custom property drawers for custom clips
  • Instead of making you decorate them directly from a custom clip inspector, Unity has some sort of internal Editor class responsible for drawing a default inspector for these fields
  • At some point in the recent past (around 2018.1 at the very latest, which is when I first tried the asset), that internal inspector-generating class was removed or became broken
  • As a result, ExposedReference fields are currently not decorated with a proper GUI disguising them as ordinary reference fields and properly filling those fields with data (exposedName).
  • Consequently, itā€™s currently impossible to reference anything in clips using ExposedReference fields, like TransformTweenClip from DefaultPlayables asset

Please correct me if Iā€™m wrong somewhere. Maybe itā€™s really a bug that just wasnā€™t noticed for a while, since none of default Timeline tracks shipping with Unity Editor use ExposedReference fields in the clips, so you can only encounter the issue while checking the Default Playables asset or writing a custom track similar to transform tween example from the talk.

Thatā€™s odd. Timeline does use ExposedReferences on Control Track clips, and I havenā€™t seen them behave that way. Iā€™ve even downloaded James example and it worked as expected (in 2018.2).

You are right about a ā€˜nakedā€™ inspector, it looks as if the drawer for ExposedReferences isnā€™t being loaded correctly. You can try a control track, and see if the Source Game Object field is working correctly. My only other suggestion off the top of my head is to file a bug. Having the repro case always makes it easier to get to the bottom of it!.

Glad to hear thatā€™s not how inspectors are supposed to look. Youā€™re right, I forgot about Control Tracks - dragging GameObjects into Control Tracks seems to create clips with a reasonable looking inspector.

Iā€™m not sure how ExposedReference field inside of that clip is filled/used (and truth to be said, Control Tracks are the one and only Timeline track type that I donā€™t yet understand at all how to use), but I suppose a different looking inspector is proof enough that this is an issue localized to Default Playables and custom playables creating following the model from it.

What can I look into next? For instance, what is the name of the drawer class thatā€™s supposed to decorate ExposedReference fields, so that I can check my project for possible conflicts and check managed source on GitHub for more ideas?

Figured it out thanks to the help from Tor Vestergaard from Sirenix - it looks like the issue was caused by the popular Odin Inspector asset taking over the drawers in this inspector. In case anyone stumbles into this thread while searching for a solution to the same issue, the fix is to create an ExposedReferenceDrawer class in any Editor folder, with the following content (which would stop Odin Inspector from taking over ExposedReference fields):

using UnityEngine;
using Sirenix.OdinInspector.Editor.Drawers;

public sealed class ExposedReferenceDrawer<TValue> : DrawWithUnityBaseDrawer<ExposedReference<TValue>>
    where TValue : UnityEngine.Object
{
}

No bugs on the Unity side here, sorry for the false alarm! :slight_smile:

2 Likes

Thanks for this!

I also went into Odin Preferences and disabled Odin for all Clip types (which seems to work - just make sure to press save to preserve the changes/show it up in version control).

My ExposedReferences were getting unset whenever the scene was unloaded and this was killing me, thanks so much for this! (OdinInspector was the culprit for me as well)

Getting a similar issue with ExposedReference and Odin in Unity 2022.3.31f1 and Odin 3.3.1.3. The ExposedReference is getting drawn strangely, and if I drop a new value in, the Timeline doesnā€™t reflect this newly set value unless I click off of it and then back on. In Play Mode I canā€™t get it to update at all. You can see it here.

OPā€™s solution does make the inspector LOOK correct, but I can no longer slot anything in. This is definitely an Odin based issue. On an empty project, ExposedReferences immediately break like this upon the addition of Odin, and return to normal when itā€™s removed.

This does seem to work, though that solution seems a bit rough if I need to do this for every Clip type I create.