Skip to content

Instantly share code, notes, and snippets.

@tkymx
Created March 7, 2021 08:27
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save tkymx/e7d65cceec76d2ec32def19fa7335367 to your computer and use it in GitHub Desktop.
CloneTimelineAsset の複製
private class TimelinePrivateMethodAndField : ITimelinePrivateMethodAndField
{
private readonly MethodInfo _timelineAddMethod;
private readonly MethodInfo _timelineRemoveMethod;
private readonly MethodInfo _trackAddMethod;
private readonly MethodInfo _trackRemoveMethod;
private readonly FieldInfo _trackParentField;
public TimelinePrivateMethodAndField()
{
GetPrivateMethodAndField(
out _timelineAddMethod,
out _timelineRemoveMethod,
out _trackAddMethod,
out _trackRemoveMethod,
out _trackParentField);
}
public void AddTrackToTimeline(TimelineAsset timelineAsset, TrackAsset trackAsset)
{
_timelineAddMethod.Invoke(timelineAsset, new object[]{trackAsset});
}
public void RemoveTrackFromTimeline(TimelineAsset timelineAsset, TrackAsset trackAsset)
{
_timelineRemoveMethod.Invoke(timelineAsset, new object[] {trackAsset});
}
public void AddClipToTrack(TrackAsset trackAsset, PlayableAsset playableAsset)
{
_trackAddMethod.Invoke(trackAsset, new object[] {playableAsset});
}
public void RemoveClipFromTrack(TrackAsset trackAsset, PlayableAsset playableAsset)
{
_trackRemoveMethod.Invoke(trackAsset, new object[] {playableAsset});
}
public void SetParentToTrack(TrackAsset trackAsset, PlayableAsset parent)
{
_trackParentField.SetValue(trackAsset, parent);
}
private static void GetPrivateMethodAndField(
out MethodInfo timelineAddMethod,
out MethodInfo timelineRemoveMethod,
out MethodInfo trackAddMethod,
out MethodInfo trackRemoveMethod,
out FieldInfo trackParentField)
{
var timelineType = typeof(TimelineAsset);
timelineAddMethod = timelineType.GetMethod("AddTrackInternal",BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic);
timelineRemoveMethod = timelineType.GetMethod("RemoveTrack",BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic);
if (timelineAddMethod == null || timelineRemoveMethod == null)
{
throw new Exception("AddTrackInternal と RemoveTrack が見つかりません");
}
var trackType = typeof(TrackAsset);
trackAddMethod = trackType.GetMethod("AddChild",BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic);
trackRemoveMethod = trackType.GetMethod("RemoveSubTrack",BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic);
trackParentField = trackType.GetField("m_Parent", BindingFlags.Instance | BindingFlags.NonPublic);
if (trackAddMethod == null || trackRemoveMethod == null || trackParentField == null)
{
throw new Exception("AddChild と RemoveSubTrack と m_Parent が見つかりません");
}
}
}
private static TimelineAsset CloneTimelineAsset(PlayableDirector playableDirector, TimelineAsset sourceAsset)
{
// 親情報の保存
var parents = sourceAsset.GetOutputTracks().Select(__ => __.parent).ToList();
// TimeLineAsset のインスタンス化
var timelineInstance = Object.Instantiate(sourceAsset);
timelineInstance.name = sourceAsset.name;
// メソッド取得
var timelinePrivateMethodAndField = new TimelinePrivateMethodAndField();
// トラックのインスタンス化
InstantiateTrack(playableDirector, timelineInstance, timelinePrivateMethodAndField);
// 親の再設定
var count = 0;
foreach (var trackAsset in sourceAsset.GetOutputTracks())
{
var parent = parents[count];
timelinePrivateMethodAndField.SetParentToTrack(trackAsset, parent);
count++;
}
return timelineInstance;
}
private static void InstantiateTrack(PlayableDirector playableDirector, TimelineAsset timelineInstance,ITimelinePrivateMethodAndField timelinePrivateMethodAndField)
{
foreach (var trackAsset in timelineInstance.GetRootTracks())
{
if (trackAsset == timelineInstance.markerTrack)
{
continue;
}
var trackInstance = Object.Instantiate<TrackAsset>(trackAsset);
trackInstance.name = trackAsset.name;
timelinePrivateMethodAndField.AddTrackToTimeline(timelineInstance, trackInstance);
timelinePrivateMethodAndField.RemoveTrackFromTimeline(timelineInstance, trackAsset);
ReplaceBinding(playableDirector, trackAsset, trackInstance);
InstantiateClipAsset(trackInstance);
InstantiateChildTrackAsset(playableDirector, trackInstance, timelinePrivateMethodAndField);
}
}
private static void InstantiateChildTrackAsset(PlayableDirector playableDirector, TrackAsset trackInstance, ITimelinePrivateMethodAndField timelinePrivateMethodAndField)
{
foreach (var childTrack in trackInstance.GetChildTracks())
{
var childTrackInstance = Object.Instantiate<TrackAsset>(childTrack);
childTrackInstance.name = childTrack.name;
timelinePrivateMethodAndField.AddClipToTrack(trackInstance, childTrackInstance);
timelinePrivateMethodAndField.RemoveClipFromTrack(trackInstance, childTrack);
ReplaceBinding(playableDirector, childTrack, childTrackInstance);
InstantiateClipAsset(trackInstance);
InstantiateChildTrackAsset(playableDirector, childTrackInstance, timelinePrivateMethodAndField);
}
}
private static void ReplaceBinding(PlayableDirector playableDirector, TrackAsset source, TrackAsset destination)
{
var genericBinding = playableDirector.GetGenericBinding(source);
playableDirector.SetGenericBinding(destination, genericBinding);
}
private static void InstantiateClipAsset(TrackAsset trackInstance)
{
foreach (var timelineClip in trackInstance.GetClips())
{
var clipInstance = Object.Instantiate(timelineClip.asset);
clipInstance.name = timelineClip.asset.name;
timelineClip.asset = clipInstance;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment