Search Unity

Unity deletes empty tracks from timelines in __internalAwake

Discussion in 'Timeline' started by KapuraIII, Apr 30, 2018.

  1. KapuraIII

    KapuraIII

    Joined:
    Oct 25, 2017
    Posts:
    11
    Is there any way for it to not do this? I'm working on automation tools that generate timelines and tracks for other disciplines to populate. Making them have to manually re-add the tracks is a drag.
     
  2. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    How are you attempting to automate that? If there are tracks that exist but use a non-existent or non-compilable script, it will not remove it. It only removes tracks that have absolutely no external reference (i.e. can't ever be 'fixed').
     
  3. KapuraIII

    KapuraIII

    Joined:
    Oct 25, 2017
    Posts:
    11
    Interesting. I have a class AttackTimeline that extends TimelineAsset, and then a custom editor that allows us to create a list of animation clips and create a timeline for each of them. The creation loop in the editor looks like this:

    Code (CSharp):
    1. // Create new attack timelines for anything that does not already have one
    2. foreach (AnimationAttackBinding aab in aabs)
    3. {
    4.     if (aab.Timeline == null)
    5.     {
    6.         string path = AssetDatabase.GetAssetPath(aab.Clip);
    7.         string filename = aab.Clip.name + NEW_ATTACK_SUFFIX;
    8.         string newPath = path.Replace(Path.GetFileName(path), filename);
    9.         newPath = AssetDatabase.GenerateUniqueAssetPath(newPath);
    10.  
    11.         Debug.LogFormat("Creating new AttackTimeline: {0}", filename);
    12.  
    13.         AttackTimeline newTimeline = CreateInstance<AttackTimeline>();
    14.         newTimeline.Initialize(aab.Clip, Director, Animator);  // Sets up the animation track and attack track
    15.         AssetDatabase.CreateAsset(newTimeline, newPath);
    16.         AssetDatabase.SaveAssets();
    17.         aab.Timeline = AssetDatabase.LoadAssetAtPath<AttackTimeline>(newPath);
    18.     }
    19. }
    The AttackTimeline's initialisation function looks like this:

    Code (CSharp):
    1. public void Initialize(AnimationClip clip, PlayableDirector director, Animator animator)
    2. {
    3.     AnimationTrack animTrack = CreateTrack<AnimationTrack>(null, "Animation Track");
    4.     animTrack.CreateClip(clip);
    5.     CreateTrack<AttackTrack>(null, "Attack Track");
    6.     CreateTrack<CritPointTrack>(null, "Crit Spawns");
    7.     CreateTrack<MotionControlTrack>(null, "Motion Control");
    8.  
    9.     AnimationTriggerName = AnimationAttackBinding.GetTriggerName(clip);
    10.     AnimationTriggerHash = Animator.StringToHash(AnimationTriggerName);
    11.  
    12.     director.SetGenericBinding(animTrack, animator.gameObject);
    13. }
    After doing this, the new timelines look as expected and work until the editor is restarted. I am beginning to think that I might need to call SaveAssets before calling Initialize. I will try that.
     
  4. KapuraIII

    KapuraIII

    Joined:
    Oct 25, 2017
    Posts:
    11
    So, after deferring the initialize until after reloading the asset the tracks remain as expected. Here's what I changed in the loop:
    Code (CSharp):
    1. AttackTimeline newTimeline = CreateInstance<AttackTimeline>();
    2. AssetDatabase.CreateAsset(newTimeline, newPath);
    3. AssetDatabase.SaveAssets();
    4. aab.Timeline = AssetDatabase.LoadAssetAtPath<AttackTimeline>(newPath);
    5. newTimeline.Initialize(aab.Clip, Director, Animator);  // Sets up the animation track and attack track
    6. EditorUtility.SetDirty(newTimeline);
    It's weird that I have to do this... it feels like a bug? I don't know, maybe that's how the Unity assets are supposed to work? (I'm in 2018.1.0f1)
     
  5. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    That's exactly what I was going to tell you! Defer the creation of tracks until after the timeline is registered to the asset database.

    Timeline will automatically make tracks subassets on creation, but if the timeline isn't in the asset database, it can't do that.

    That's a known issue when creating timelines dynamically, and something we should fix a way to fix, or at least detect and warn about.