181 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			181 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|  | 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) | ||
|  |             { | ||
|  |                 PlayableDirector[] directorsInScene = GetAllDirectorsInScene(); | ||
|  |                 IEnumerable<TimelineAsset> timelines = directorsInScene.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++; | ||
|  |                                 } | ||
|  |                             } | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         static PlayableDirector[] GetAllDirectorsInScene() | ||
|  |         { | ||
|  | #if UNITY_2023_1_OR_NEWER | ||
|  |             return UnityEngine.Object.FindObjectsByType<PlayableDirector>(UnityEngine.FindObjectsSortMode.None); | ||
|  | #else | ||
|  |             return UnityEngine.Object.FindObjectsOfType<PlayableDirector>(); | ||
|  | #endif | ||
|  |         } | ||
|  | 
 | ||
|  |         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); | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | } |