| using System; |
| using System.Collections.Generic; |
| using System.Linq; |
| using UnityEditor.Build; |
| using UnityEditor.Build.Reporting; |
| using UnityEngine.Playables; |
| using UnityEngine.SceneManagement; |
| using UnityEngine.Timeline; |
|
|
| namespace UnityEditor.Timeline.Analytics |
| { |
| class TimelineSceneInfo |
| { |
| public Dictionary<string, int> trackCount = new Dictionary<string, int> |
| { |
| {"ActivationTrack", 0}, |
| {"AnimationTrack", 0}, |
| {"AudioTrack", 0}, |
| {"ControlTrack", 0}, |
| {"PlayableTrack", 0}, |
| {"UserType", 0}, |
| {"Other", 0} |
| }; |
|
|
| public Dictionary<string, int> userTrackTypesCount = new Dictionary<string, int>(); |
| public HashSet<TimelineAsset> uniqueDirectors = new HashSet<TimelineAsset>(); |
| public int numTracks = 0; |
| public int minDuration = int.MaxValue; |
| public int maxDuration = int.MinValue; |
| public int minNumTracks = int.MaxValue; |
| public int maxNumTracks = int.MinValue; |
| public int numRecorded = 0; |
| } |
|
|
| [Serializable] |
| struct TrackInfo |
| { |
| public string name; |
| public double percent; |
| } |
|
|
| [Serializable] |
| class TimelineEventInfo |
| { |
| public int num_timelines; |
| public int min_duration, max_duration; |
| public int min_num_tracks, max_num_tracks; |
| public double recorded_percent; |
| public List<TrackInfo> track_info = new List<TrackInfo>(); |
| public string most_popular_user_track = string.Empty; |
|
|
| public TimelineEventInfo(TimelineSceneInfo sceneInfo) |
| { |
| num_timelines = sceneInfo.uniqueDirectors.Count; |
| min_duration = sceneInfo.minDuration; |
| max_duration = sceneInfo.maxDuration; |
| min_num_tracks = sceneInfo.minNumTracks; |
| max_num_tracks = sceneInfo.maxNumTracks; |
| recorded_percent = Math.Round(100.0 * sceneInfo.numRecorded / sceneInfo.numTracks, 1); |
|
|
| foreach (KeyValuePair<string, int> kv in sceneInfo.trackCount.Where(x => x.Value > 0)) |
| { |
| track_info.Add(new TrackInfo() |
| { |
| name = kv.Key, |
| percent = Math.Round(100.0 * kv.Value / sceneInfo.numTracks, 1) |
| }); |
| } |
|
|
| if (sceneInfo.userTrackTypesCount.Any()) |
| { |
| most_popular_user_track = sceneInfo.userTrackTypesCount |
| .First(x => x.Value == sceneInfo.userTrackTypesCount.Values.Max()).Key; |
| } |
| } |
|
|
| public static bool IsUserType(Type t) |
| { |
| string nameSpace = t.Namespace; |
| return string.IsNullOrEmpty(nameSpace) || !nameSpace.StartsWith("UnityEngine.Timeline"); |
| } |
| } |
|
|
|
|
| static class TimelineAnalytics |
| { |
| static TimelineSceneInfo _timelineSceneInfo = new TimelineSceneInfo(); |
|
|
| class TimelineAnalyticsPreProcess : IPreprocessBuildWithReport |
| { |
| public int callbackOrder { get { return 0; } } |
| public void OnPreprocessBuild(BuildReport report) |
| { |
| _timelineSceneInfo = new TimelineSceneInfo(); |
| } |
| } |
|
|
| class TimelineAnalyticsProcess : IProcessSceneWithReport |
| { |
| public int callbackOrder |
| { |
| get { return 0; } |
| } |
|
|
| public void OnProcessScene(Scene scene, BuildReport report) |
| { |
| var timelines = UnityEngine.Object.FindObjectsOfType<PlayableDirector>().Select(pd => pd.playableAsset).OfType<TimelineAsset>().Distinct(); |
|
|
| foreach (var timeline in timelines) |
| { |
| if (_timelineSceneInfo.uniqueDirectors.Add(timeline)) |
| { |
| _timelineSceneInfo.numTracks += timeline.flattenedTracks.Count(); |
| _timelineSceneInfo.minDuration = Math.Min(_timelineSceneInfo.minDuration, (int)(timeline.duration * 1000)); |
| _timelineSceneInfo.maxDuration = Math.Max(_timelineSceneInfo.maxDuration, (int)(timeline.duration * 1000)); |
| _timelineSceneInfo.minNumTracks = Math.Min(_timelineSceneInfo.minNumTracks, timeline.flattenedTracks.Count()); |
| _timelineSceneInfo.maxNumTracks = Math.Max(_timelineSceneInfo.maxNumTracks, timeline.flattenedTracks.Count()); |
|
|
| foreach (var track in timeline.flattenedTracks) |
| { |
| string key = track.GetType().Name; |
| if (_timelineSceneInfo.trackCount.ContainsKey(key)) |
| { |
| _timelineSceneInfo.trackCount[key]++; |
| } |
| else |
| { |
| if (TimelineEventInfo.IsUserType(track.GetType())) |
| { |
| _timelineSceneInfo.trackCount["UserType"]++; |
| if (_timelineSceneInfo.userTrackTypesCount.ContainsKey(key)) |
| _timelineSceneInfo.userTrackTypesCount[key]++; |
| else |
| _timelineSceneInfo.userTrackTypesCount[key] = 1; |
| } |
| else |
| _timelineSceneInfo.trackCount["Other"]++; |
| } |
|
|
| if (track.clips.Any(x => x.recordable)) |
| _timelineSceneInfo.numRecorded++; |
| else |
| { |
| var animationTrack = track as AnimationTrack; |
| if (animationTrack != null) |
| { |
| if (animationTrack.CanConvertToClipMode()) |
| _timelineSceneInfo.numRecorded++; |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
|
|
| class TimelineAnalyticsPostProcess : IPostprocessBuildWithReport |
| { |
| public int callbackOrder { get { return 0; } } |
| public void OnPostprocessBuild(BuildReport report) |
| { |
| if (_timelineSceneInfo.uniqueDirectors.Count > 0) |
| { |
| var timelineEvent = new TimelineEventInfo(_timelineSceneInfo); |
| EditorAnalytics.SendEventTimelineInfo(timelineEvent); |
| } |
| } |
| } |
| } |
| } |
|
|