Unity Timeline(Playable Director)を複製した際にGameObjectのバインドがはずれてしまう。。

#初めに
プロジェクト
Timeline(Playable Director)を複製した際にGameObjectのバインドがはずれてしまう。。



##どんな現象かと言うと。
１．まず、適当にCubeが拡縮するアニメーション作ります。

![time01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37068/498db66d-107d-414f-6bf6-89eb5252ba4c.gif)

２、同じようなシーンを作りたくて、シーンをコピーして複製したシーンを開きます。

![time02.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37068/83f56aa3-4741-1136-a2c7-a0910b32a869.gif)

３，複製元のTimeline(Playable Director)と同じになってしまうので、プロジェクトウィンドウでTimeline(Playable Director)も
コピーし複製先のシーンのTimeline(Playable Director)にアタッチすると１，で作ったアニメーションのGameObjectのバインドが外れてしまう。

![time03.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37068/6cfcfdd3-3a6b-e638-7948-e5e30c416137.gif)


### Unity Forumsで 解決
意外とあっさり、同じことで悩んでいる方がいて、解決しました。

https://forum.unity.com/threads/duplicating-a-timeline-loses-all-the-bindings-unity-v2017-2-0b6.488138/

seant_unityさんが対策のスクリプト書いてくれてますが、Timeline(Playable Director)の複製を作って、、HierarchyにTimeline(Playable Director)のCloneをつくり、同じパスにTimeline(Playable Director)のオブジェクトもCloneを作ってくれるものでした。

そのあと、書き込みでも動作しないとか書き込みがあるので、割と最近の投稿のRibさんの投稿を採用することしました。


#### こんな感じ
やったのは、シーンを複製して複製先のシーンでTimeline(Playable Director)の複製を行っただけ

![time04.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37068/b01629e0-5d96-f3d2-e8b8-4ad6ef38682e.gif)

##### スクリプト


```c#

using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
using UnityEditor;

public class DuplicateTimeline : EditorWindow
{
    [MenuItem("imeline/Duplicate Timeline", true)]
    private static bool DupTimelineValidate()
    {
        if (UnityEditor.Selection.activeObject as GameObject == null)
        {
            Debug.Log("Null active object");
            return false;
        }

        GameObject playableDirectorObj = UnityEditor.Selection.activeObject as GameObject;

        PlayableDirector playableDirector = playableDirectorObj.GetComponent<PlayableDirector>();
        if (playableDirector == null)
        {
            Debug.Log("Null playableDirector");
            return false;
        }

        TimelineAsset timelineAsset = playableDirector.playableAsset as TimelineAsset;
        if (timelineAsset == null)
        {
            Debug.Log("Null timelineAsset");
            return false;
        }

        string path = AssetDatabase.GetAssetPath(timelineAsset);
        if (string.IsNullOrEmpty(path))
        {
            Debug.Log("Null timeline asset path");
            return false;
        }

        return true;
    }

    [MenuItem("Timeline/Duplicate Timeline")]
    public static void DupTimeline()
    {
        // 再生可能なディレクターを取得し、タイムラインを取得します
        GameObject playableDirectorObj = UnityEditor.Selection.activeObject as GameObject;
        PlayableDirector playableDirector = playableDirectorObj.GetComponent<PlayableDirector>();
        TimelineAsset timelineAsset = playableDirector.playableAsset as TimelineAsset;

        // 複製
        string path = AssetDatabase.GetAssetPath(timelineAsset);
        string newPath = path.Replace(".", "(Clone).");
        if (!AssetDatabase.CopyAsset(path, newPath))
        {
            Debug.LogError("Couldn't Clone Asset");
            return;
        }

        // バインディングのコピー
        TimelineAsset newTimelineAsset = AssetDatabase.LoadMainAssetAtPath(newPath) as TimelineAsset;
        PlayableBinding[] oldBindings = timelineAsset.outputs.ToArray();
        PlayableBinding[] newBindings = newTimelineAsset.outputs.ToArray();
        for (int i = 0; i < oldBindings.Length; i++)
        {
            playableDirector.playableAsset = timelineAsset;
            Object boundTo = playableDirector.GetGenericBinding(oldBindings[i].sourceObject);

            playableDirector.playableAsset = newTimelineAsset;
            playableDirector.SetGenericBinding(newBindings[i].sourceObject, boundTo);
        }

        // 公開された参照をコピーする
        playableDirector.playableAsset = newTimelineAsset;
        foreach (TrackAsset newTrackAsset in newTimelineAsset.GetRootTracks())
        {
            foreach (TimelineClip newClip in newTrackAsset.GetClips())
            {
                foreach (FieldInfo fieldInfo in newClip.asset.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
                {
                    if (fieldInfo.FieldType.IsGenericType && fieldInfo.FieldType.GetGenericTypeDefinition() == typeof(ExposedReference<>))
                    {
                        // 古い公開名を取得する
                        object exposedReference = fieldInfo.GetValue(newClip.asset);
                        PropertyName oldExposedName = (PropertyName)fieldInfo.FieldType
                            .GetField("exposedName")
                            .GetValue(exposedReference);
                        bool isValid;

                        // 古い公開値を取得する
                        Object oldExposedValue = playableDirector.GetReferenceValue(oldExposedName, out isValid);
                        if (!isValid)
                        {
                            Debug.LogError("Failed to copy exposed references to duplicate timeline. Could not find: " + oldExposedName);
                            return;
                        }

                        // 構造体のexposedNameを置き換えます
                        PropertyName newExposedName = new PropertyName(UnityEditor.GUID.Generate().ToString());
                        fieldInfo.FieldType
                            .GetField("exposedName")
                            .SetValue(exposedReference, newExposedName);

                        // ExposedReferenceを設定します
                        fieldInfo.SetValue(newClip.asset, exposedReference);

                        // PlayableDirectorのリファレンスを設定する
                        playableDirector.SetReferenceValue(newExposedName, oldExposedValue);
                    }
                }
            }
        }
    }
}
```

#####最後に
もし、こんな事しなくても出来るとか、オペレーションで回避出来ると言う話であれば、どなたか教えて下さい。

要望とか多いので、ツールやら、Unityのエディタ拡張が最近多いな。。