Search Unity

Feedback User managed Timeline playable still requires a PlayableDirector for Markers

Discussion in 'Timeline' started by Andrew-Carvalho, Nov 17, 2021.

  1. Andrew-Carvalho

    Andrew-Carvalho

    Joined:
    Apr 22, 2013
    Posts:
    44
    Hey! I'm currently working on using Timeline to drive some logic that needs to be synchronized to animation to take advantage of the editor tools for easy iterations.

    At runtime, I drive the character using an in house Playables script that builds the graph and lets me blend between a basic movement animation controller and an override playable (a clip, another controller, or a playable created from a timeline). I do not use a PlayableDirector and instead reference the playable assets directly. For the most part this all works and, from my understanding of some older threads, is an intended use case.

    The issue is that I have added a custom marker to one of my logic tracks and am getting a NullReferenceException inside NotificationUtilities.CreateNotificationsPlayable, which is used internally to the timeline track. Below is the method in question from the Timeline package, and it appears that the director is only being used to access the serialized length and extrapolation more of the playable (lines 13 and 14).

    Code (CSharp):
    1. public static ScriptPlayable<TimeNotificationBehaviour> CreateNotificationsPlayable(PlayableGraph graph, IEnumerable<IMarker> markers, GameObject go)
    2. {
    3.     var notificationPlayable = ScriptPlayable<TimeNotificationBehaviour>.Null;
    4.     var director = go.GetComponent<PlayableDirector>();
    5.     foreach (var e in markers)
    6.     {
    7.         var notif = e as INotification;
    8.         if (notif == null)
    9.             continue;
    10.  
    11.         if (notificationPlayable.Equals(ScriptPlayable<TimeNotificationBehaviour>.Null))
    12.         {
    13.             notificationPlayable = TimeNotificationBehaviour.Create(graph,
    14.                 director.playableAsset.duration, director.extrapolationMode);
    15.         }
    16.  
    17.         var time = (DiscreteTime)e.time;
    18.         var tlDuration = (DiscreteTime)director.playableAsset.duration;
    19.         if (time >= tlDuration && time <= tlDuration.OneTickAfter() && tlDuration != 0)
    20.         {
    21.             time = tlDuration.OneTickBefore();
    22.         }
    23.  
    24.         var notificationOptionProvider = e as INotificationOptionProvider;
    25.         if (notificationOptionProvider != null)
    26.         {
    27.             notificationPlayable.GetBehaviour().AddNotification((double)time, notif, notificationOptionProvider.flags);
    28.         }
    29.         else
    30.         {
    31.             notificationPlayable.GetBehaviour().AddNotification((double)time, notif);
    32.         }
    33.     }
    34.  
    35.     return notificationPlayable;
    36. }
    Since there is no way to override how notifications are created on the timeline (the TrackAsset.CreateNotificationsPlayable is private) this behaviour can't be changed. Considering how everything else in Timeline seems to support not having a PlayableDirector, this implementation seems like an oversight, though I'm not sure if it would be considered a bug. Some clarification would be appreciated.

    A workaround is to have a PlayableDirector attached to the game object and update it's referenced playable asset whenever a new timeline is played, but it seems like a bit of unnecessary overhead. I'm happy to do something else if anyone has a better suggestion, however.
     
    ryanmillerca likes this.
  2. DavidGeoffroy

    DavidGeoffroy

    Unity Technologies

    Joined:
    Sep 9, 2014
    Posts:
    542
    Thanks for bringing this to our attention.

    We can remove the explicit need for a PlayableDirector, but in cases where you don't have it, the looping behaviour of notifications may not work correctly if the deltaTime between evaluations is bigger than the length of the Timeline.

    I think that's ok, as looping is normally managed by the PlayableDirector anyway.
    Since this change has no outward impact on existing behaviour, we can ship this as a bug fix.

    Unless there are compelling use cases to expose more notifications-related methods, we're probably going to keep them internal to keep our API surface under control. But if you have any, feel free to share them.

    On a more philosophical note:

    Timeline+PlayableDirector is the product that we ship and test. We try our best not to explicitly block other creative use cases for Timeline, but we don't actively test for that, except for regression tests when we ship bugfixes (like the one we're about to land in this case).

    We understand that some people use Timeline in other ways, but we don't guarantee a coherent experience outside of the main worfklow, especially as we add new features.
     
    ryanmillerca likes this.
  3. Andrew-Carvalho

    Andrew-Carvalho

    Joined:
    Apr 22, 2013
    Posts:
    44
    Thanks for the response @DavidGeoffroy and this is wonderful news! I know implementation decisions aren't necessarily bugs (and often have specific reasoning behind them) so this is a nice surprise.

    I completely understand. I hesitated on posting because our use case isn't common, but this was one of two *very* small hiccups that came up out of many, many things that worked without any issue while implementing a system to leverage all the benefits of Timeline on top of our own Playables controller logic. I appreciate the transparency on your approach and your willingness to investigate and integrate the request.

    Looking forward to the update!
     
    ryanmillerca likes this.