using System; using UnityEngine; using UnityEngine.Playables; using UnityEngine.Timeline; #if UNITY_EDITOR using System.Reflection; using UnityEditor; #endif namespace FT.Timeline { [Serializable] public class LeviathanVideoTrackMixerBehaviour : PlayableBehaviour { } [Serializable] [TrackColor(0.82f, 0.42f, 0.62f)] [TrackClipType(typeof(LeviathanVideoPlayableAsset))] [TrackBindingType(typeof(LeviathanVideoDecoderBase))] [ExcludeFromPreset] public class LeviathanVideoTrack : TrackAsset { public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount) { return ScriptPlayable.Create(graph, inputCount); } protected override void OnCreateClip(TimelineClip clip) { clip.displayName = "Leviathan Video"; if (clip.asset is LeviathanVideoPlayableAsset asset) { #if UNITY_EDITOR ApplyNewClipFromBoundDecoder(clip, asset); #endif clip.duration = asset.clipDurationSeconds; } base.OnCreateClip(clip); } #if UNITY_EDITOR /// /// 新建 Clip 时:从当前 Timeline 窗口正在编辑的 Director 上读取本轨绑定解码器,同步 Video Override 与片段时长。 /// private void ApplyNewClipFromBoundDecoder(TimelineClip clip, LeviathanVideoPlayableAsset asset) { var director = TryGetTimelineInspectedDirector(); if (director == null) return; var decoder = director.GetGenericBinding(this) as LeviathanVideoDecoderBase; if (decoder == null) return; if (decoder.bytesFile != null) asset.videoOverride = decoder.bytesFile; if (LeviathanVideoPlayableAsset.TryGetClipDurationSecondsFromDecoder(decoder, out var seconds) && seconds > 0.0001) asset.clipDurationSeconds = seconds; EditorUtility.SetDirty(asset); if (timelineAsset != null) EditorUtility.SetDirty(timelineAsset); } private static PlayableDirector TryGetTimelineInspectedDirector() { foreach (var asm in System.AppDomain.CurrentDomain.GetAssemblies()) { var t = asm.GetType("UnityEditor.Timeline.TimelineEditor"); if (t == null) continue; var p = t.GetProperty("inspectedDirector", BindingFlags.Public | BindingFlags.Static); return p?.GetValue(null) as PlayableDirector; } return null; } #endif #if UNITY_EDITOR public override void GatherProperties(PlayableDirector director, IPropertyCollector driver) { var bound = director.GetGenericBinding(this) as LeviathanVideoDecoderBase; if (bound != null) { driver.AddFromComponent(bound.gameObject, bound); } base.GatherProperties(director, driver); } #endif } }