using System; using System.Collections.Generic; using System.ComponentModel; using UnityEngine; using UnityEngine.Playables; using UnityEngine.Timeline; namespace UnityEditor.Recorder.Timeline { /// /// Use this class to manage Recorder Clip Timeline integration. /// [DisplayName("Recorder Clip")] public class RecorderClip : PlayableAsset, ITimelineClipAsset, ISerializationCallbackReceiver { /// /// Indicates the Recorder Settings instance used for this Clip. /// [SerializeField] public RecorderSettings settings; readonly SceneHook m_SceneHook = new SceneHook(Guid.NewGuid().ToString()); Type recorderType { get { return settings == null ? null : RecordersInventory.GetRecorderInfo(settings.GetType()).recorderType; } } /// /// Recorder does not support any clip features. /// For more information see: https://docs.unity3d.com/2018.1/Documentation/ScriptReference/Timeline.ClipCaps.html /// public ClipCaps clipCaps { get { return ClipCaps.None; } } /// /// For more information see: https://docs.unity3d.com/ScriptReference/Playables.PlayableAsset.CreatePlayable.html /// /// The Playable Graph. /// The GameObject containing the PlayableDirector. /// The playable that drives the AlembicStreamPlayer. public override Playable CreatePlayable(PlayableGraph graph, GameObject owner) { var playable = ScriptPlayable.Create(graph); var behaviour = playable.GetBehaviour(); if (recorderType != null && UnityHelpers.IsPlaying()) { behaviour.session = m_SceneHook.CreateRecorderSession(settings); } return playable; } /// /// This is called when the Recorder Clip is being destroyed. /// For more information see: https://docs.unity3d.com/ScriptReference/ScriptableObject.OnDestroy.html /// public void OnDestroy() { #if UNITY_EDITOR var path = AssetDatabase.GetAssetPath(this); if (string.IsNullOrEmpty(path)) return; var objs = AssetDatabase.LoadAllAssetsAtPath(path); foreach (var obj in objs) { if (obj is RecorderClip rc && rc != this && rc.settings == settings) { return; } } UnityHelpers.Destroy(settings, true); #endif } // Find the timeline asset that matches this clip internal TimelineAsset FindTimelineAsset() { if (!AssetDatabase.Contains(this)) return null; var path = AssetDatabase.GetAssetPath(this); var objs = AssetDatabase.LoadAllAssetsAtPath(path); foreach (var obj in objs) { if (obj != null && obj is TimelineAsset) return obj as TimelineAsset; } return null; } internal void PushTimelineIntoRecorder(TimelineAsset timelineAsset) { if (settings == null || timelineAsset == null) return; settings.FrameRate = (float)timelineAsset.editorSettings.frameRate; settings.FrameRatePlayback = FrameRatePlayback.Constant; settings.CapFrameRate = true; } private void OnEnable() { PushTimelineIntoRecorder(FindTimelineAsset()); } /// /// This is called before the Recorder Clip object is serialized. /// For more information see: https://docs.unity3d.com/ScriptReference/ISerializationCallbackReceiver.OnBeforeSerialize.html /// public void OnBeforeSerialize() { // Nothing, we need to keep these methods to avoid changing the signature of RecorderClip for the Public API } /// /// This is called after the Recorder Clip object has been deserialized. /// For more information see: https://docs.unity3d.com/ScriptReference/ISerializationCallbackReceiver.OnAfterDeserialize.html /// public void OnAfterDeserialize() { // Nothing, we need to keep these methods to avoid changing the signature of RecorderClip for the Public API } } }