Search Unity

  1. Unity 2019.1 beta is now available.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. We're looking for insight from anyone who has experience with game testing to help us better Unity. Take our survey here. If chosen to participate you'll be entered into a sweepstake to win an Amazon gift card.
    Dismiss Notice
  4. Want to provide direct feedback to the Unity team? Join the Unity Advisory Panel.
    Dismiss Notice
  5. Unity 2018.3 is now released.
    Dismiss Notice
  6. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice

Duplicating a Timeline loses all the Bindings Unity v2017.2.0b6

Discussion in 'Timeline' started by tezza2k1, Aug 14, 2017.

  1. tezza2k1

    tezza2k1

    Joined:
    Feb 16, 2017
    Posts:
    13
    (Unity v2017.2.0b6)

    I dread making a new timeline because I will need to hunt for all the hierarchy objects and re-bind them. It should be a stress free process but it is not.

    There seems no particular reason that the duplication mechanism could not also duplicate the bindings.

    It makes workflow that much slower, because you have to re-find and re-bind the targets. I have chosen 2 bindings here, but my production Timlines have many more.

    I have a scripted sequence using a few common objects. So the Timelines are very similar, but I have at least 15 timelines with many tracks each.

    If you can follow my simplified example timeline:

    1. Audio Track - One speaks - Bound to an AudioSource A
    2. Animation Track - Another animates - Bound to an AnimationController B

    There is a problem, that when I duplicate a Timeline, the bindings are lost.

    So when I duplicate the example above, there is a Timeline and it has two tracks. 1. AudioTrack, 2. Animation Track. But the duplicate is bound to neither AudioSource A nor AnimationController B

    I have to hit the heirarchy pane, locate both AudioSource A and AnimationController B and drag them to their respective slots.
     
  2. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    688
    The reason for this is the asset does not include any bindings. The tracks are themselves assets, and new tracks are made. We should add a 'duplicate with bindings option', but to help you out here is a helper script that will copy a playableDirector, timeline, and all the bindings.



    Code (CSharp):
    1.    
    2. public class DuplicateTimeline
    3. {
    4.     [MenuItem("Timeline/Duplicate With Bindings", true)]
    5.     public static bool DuplicateWithBindingsValidate()
    6.     {
    7.         if (UnityEditor.Selection.activeGameObject == null)
    8.             return false;
    9.  
    10.         var playableDirector = UnityEditor.Selection.activeGameObject.GetComponent<PlayableDirector>();
    11.         if (playableDirector == null)
    12.             return false;
    13.  
    14.         var playableAsset = playableDirector.playableAsset;
    15.         if (playableAsset == null)
    16.             return false;
    17.  
    18.         var path = AssetDatabase.GetAssetPath(playableAsset);
    19.         if (string.IsNullOrEmpty(path))
    20.             return false;
    21.  
    22.         return true;
    23.     }
    24.  
    25.     [MenuItem("Timeline/Duplicate With Bindings")]
    26.     public static void DuplicateWithBindings()
    27.     {
    28.         if (UnityEditor.Selection.activeGameObject == null)
    29.             return;
    30.  
    31.         var playableDirector = UnityEditor.Selection.activeGameObject.GetComponent<PlayableDirector>();
    32.         if (playableDirector == null)
    33.             return;
    34.  
    35.         var playableAsset = playableDirector.playableAsset;
    36.         if (playableAsset == null)
    37.             return;
    38.  
    39.         var path = AssetDatabase.GetAssetPath(playableAsset);
    40.         if (string.IsNullOrEmpty(path))
    41.             return;
    42.  
    43.         string newPath = path.Replace(".", "(Clone).");
    44.         if (!AssetDatabase.CopyAsset(path, newPath))
    45.         {
    46.             Debug.LogError("Couldn't Clone Asset");
    47.             return;
    48.         }
    49.  
    50.         var newPlayableAsset = AssetDatabase.LoadMainAssetAtPath(newPath) as PlayableAsset;
    51.         var gameObject = GameObject.Instantiate(UnityEditor.Selection.activeGameObject);
    52.         var newPlayableDirector = gameObject.GetComponent<PlayableDirector>();
    53.         newPlayableDirector.playableAsset = newPlayableAsset;
    54.  
    55.         var oldBindings = playableAsset.outputs.ToArray();
    56.         var newBindings = newPlayableAsset.outputs.ToArray();
    57.  
    58.         for (int i = 0; i < oldBindings.Length; i++)
    59.         {
    60.             newPlayableDirector.SetGenericBinding(newBindings[i].sourceObject,
    61.                     playableDirector.GetGenericBinding(oldBindings[i].sourceObject)
    62.                 );
    63.         }
    64.     }
    65. }
    66.  
     
    truebototics likes this.
  3. tezza2k1

    tezza2k1

    Joined:
    Feb 16, 2017
    Posts:
    13
    Thanks a lot Sean !! ( I guess from your username ). That worked a treat. There was a small compilation error in your script, but I am using the experimental 4.6 .Net version so that may be it. There was no ToArray() method on the outputs.

    For other forum users, I have included my fixes here :

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using UnityEditor;
    4. using UnityEngine.Playables ;
    5.  
    6. ---------------------
    7.  
    8. var oldBindings = playableAsset.    outputs.GetEnumerator();
    9. var newBindings = newPlayableAsset. outputs.GetEnumerator();
    10.  
    11.  
    12. while( oldBindings.MoveNext() )
    13. {
    14.     var oldBindings_sourceObject = oldBindings.Current.sourceObject ;
    15.  
    16.     newBindings.MoveNext();
    17.  
    18.     var newBindings_sourceObject = newBindings.Current.sourceObject ;
    19.  
    20.  
    21.     newPlayableDirector.SetGenericBinding(
    22.         newBindings_sourceObject,
    23.         playableDirector.GetGenericBinding( oldBindings_sourceObject )
    24.     );
    25. }
     
    Flurgle and truebototics like this.
  4. truebototics

    truebototics

    Joined:
    Jan 2, 2016
    Posts:
    20
    So awesome. Thank you.... This is exactly what I was looking for...

    Question though - where would I put / paste this code?
     
  5. truebototics

    truebototics

    Joined:
    Jan 2, 2016
    Posts:
    20
    Got it working.. Here's the combination of the two scripts for those interested.
    Thanks to @Tezza and @seant_unity for the code.

    Unity Timeline is amazing!!!!

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using UnityEngine.Playables ;
    4.  
    5. public class DuplicateTimeline
    6. {
    7.     [MenuItem("Timeline/Duplicate With Bindings", true)]
    8.     public static bool DuplicateWithBindingsValidate()
    9.     {
    10.         if (UnityEditor.Selection.activeGameObject == null)
    11.             return false;
    12.  
    13.         var playableDirector = UnityEditor.Selection.activeGameObject.GetComponent<PlayableDirector>();
    14.         if (playableDirector == null)
    15.             return false;
    16.  
    17.         var playableAsset = playableDirector.playableAsset;
    18.         if (playableAsset == null)
    19.             return false;
    20.  
    21.         var path = AssetDatabase.GetAssetPath(playableAsset);
    22.         if (string.IsNullOrEmpty(path))
    23.             return false;
    24.  
    25.         return true;
    26.     }
    27.  
    28.     [MenuItem("Timeline/Duplicate With Bindings")]
    29.     public static void DuplicateWithBindings()
    30.     {
    31.         if (UnityEditor.Selection.activeGameObject == null)
    32.             return;
    33.  
    34.         var playableDirector = UnityEditor.Selection.activeGameObject.GetComponent<PlayableDirector>();
    35.         if (playableDirector == null)
    36.             return;
    37.  
    38.         var playableAsset = playableDirector.playableAsset;
    39.         if (playableAsset == null)
    40.             return;
    41.  
    42.         var path = AssetDatabase.GetAssetPath(playableAsset);
    43.         if (string.IsNullOrEmpty(path))
    44.             return;
    45.  
    46.         string newPath = path.Replace(".", "(Clone).");
    47.         if (!AssetDatabase.CopyAsset(path, newPath))
    48.         {
    49.             Debug.LogError("Couldn't Clone Asset");
    50.             return;
    51.         }
    52.  
    53.         var newPlayableAsset = AssetDatabase.LoadMainAssetAtPath(newPath) as PlayableAsset;
    54.         var gameObject = GameObject.Instantiate(UnityEditor.Selection.activeGameObject);
    55.         var newPlayableDirector = gameObject.GetComponent<PlayableDirector>();
    56.         newPlayableDirector.playableAsset = newPlayableAsset;
    57.  
    58.         var oldBindings = playableAsset.    outputs.GetEnumerator();
    59.         var newBindings = newPlayableAsset. outputs.GetEnumerator();
    60.  
    61.  
    62.         while( oldBindings.MoveNext() )
    63.         {
    64.             var oldBindings_sourceObject = oldBindings.Current.sourceObject ;
    65.  
    66.             newBindings.MoveNext();
    67.  
    68.             var newBindings_sourceObject = newBindings.Current.sourceObject ;
    69.  
    70.  
    71.             newPlayableDirector.SetGenericBinding(
    72.                 newBindings_sourceObject,
    73.                 playableDirector.GetGenericBinding( oldBindings_sourceObject )
    74.             );
    75.         }
    76.     }
    77. }
     
    Flurgle likes this.
  6. awasem

    awasem

    Joined:
    Nov 25, 2015
    Posts:
    3
    Create a C# script, copy and paste this code into MonoDevelop when it opens, and name it something like duplicateTimeline. Now with your timeline selected from the Timeline menu at the top there is an option to Duplicate With Bindings. Awesome! Thanks @Tezza and @seant_unity for the code.
     
  7. awasem

    awasem

    Joined:
    Nov 25, 2015
    Posts:
    3
    Any way to edit this script to keep the duplicated timeline gameObject on the canvas? When duplicate a timeline asset it moves out of canvas. Then when I bring it back into the canvas its the wrong size.
     
  8. GonzoGan

    GonzoGan

    Joined:
    Mar 15, 2013
    Posts:
    38
    Not working on Unity 2018.2.1f1
     
  9. AdamBL

    AdamBL

    Joined:
    Oct 27, 2016
    Posts:
    29
    Hey @GonzoGan I think it is working in 2018.2, it just works in a kind of weird way. Some of the issues I had were:

    1. You need to have the GameObject that has the Playable Director component selected in your scene in order to duplicate it (not in your Project window)
    2. When you duplicate it, it creates a Clone GameObject in your scene with the duplicated Timeline in its PlayableDirector slot (rather than modifying the original GameObject)
    3. Most confusing is the fact that the duplicated Timeline still references the original GameObjects, even if it created new ones.
    So in our scene, we have all our animated elements as children of the object with the Playable Director component, and when we duplicated the Timeline it duplicated all those objects. However, the new Timeline still controlled the original objects, so instead of using the Cloned object, I simply copied the Playable Director component and pasted it on the original parent object.
     
  10. Kareeem

    Kareeem

    Joined:
    Mar 1, 2013
    Posts:
    19
    The script works without any issues in 2018.2.15f1
     
  11. Flurgle

    Flurgle

    Joined:
    May 16, 2016
    Posts:
    327
    Duplicating with bindings is not working in Unity 2019.1a10 either
     
  12. MikeFish

    MikeFish

    Joined:
    Oct 24, 2015
    Posts:
    9
    I could need some help.
    It's not working for me

    Unity 2018.3.4f1

    It clones the Timeline but without any bindings, it is doing exactly the same as ctrl D in the project window.
    I followed all instructions I could find here without any positive result.

    any help would be very appreciated.
    thanks,
    Mike

    ----------------------------
    Edit:
    my bad,
    wasn't noticing that only the new created Director hold all bindings,
    what is logical when you think about it.
    So, yeah it is working.
     
    Last edited: Feb 6, 2019
    thierry_unity likes this.
  13. PawleyBoboli

    PawleyBoboli

    Joined:
    Jan 27, 2015
    Posts:
    6
    This works great and I get no errors compiling it or using it during production. The Timeline Menu Item shows up in my editor and the duplication-with-bindings works perfect. Thanks for this!

    However, I do get errors when trying to publish a Build to WebGL. The build fails with this error in the console:

    "Assets/Timelines/DuplicateTimeline.cs(7,6): error CS0246: The type or namespace name 'MenuItem' could not be found (are you missing a using directive or an assembly reference?)"

    I cannot find any problems with the script, and I found that I can build if I just remove it from the project. Not a big issue, but if anyone has a solution so the script does not need removing, I would appreciate any info.

    Thanks.


     
  14. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    688
    Put the script in a folder named Editor. It will be excluded from player builds then. Or if you need it in a player, wrap the using UnityEditor; and [MenuItem(..)] lines with a #if UNITY_EDITOR / #endif.