A game about forced loneliness, made by TACStudios
at master 180 lines 7.1 kB view raw
1using System; 2using System.Collections.Generic; 3using System.Linq; 4using UnityEditor.Build; 5using UnityEditor.Build.Reporting; 6using UnityEngine.Playables; 7using UnityEngine.SceneManagement; 8using UnityEngine.Timeline; 9 10namespace UnityEditor.Timeline.Analytics 11{ 12 class TimelineSceneInfo 13 { 14 public Dictionary<string, int> trackCount = new Dictionary<string, int> 15 { 16 {"ActivationTrack", 0}, 17 {"AnimationTrack", 0}, 18 {"AudioTrack", 0}, 19 {"ControlTrack", 0}, 20 {"PlayableTrack", 0}, 21 {"UserType", 0}, 22 {"Other", 0} 23 }; 24 25 public Dictionary<string, int> userTrackTypesCount = new Dictionary<string, int>(); 26 public HashSet<TimelineAsset> uniqueDirectors = new HashSet<TimelineAsset>(); 27 public int numTracks = 0; 28 public int minDuration = int.MaxValue; 29 public int maxDuration = int.MinValue; 30 public int minNumTracks = int.MaxValue; 31 public int maxNumTracks = int.MinValue; 32 public int numRecorded = 0; 33 } 34 35 [Serializable] 36 struct TrackInfo 37 { 38 public string name; 39 public double percent; 40 } 41 42 [Serializable] 43 class TimelineEventInfo 44 { 45 public int num_timelines; 46 public int min_duration, max_duration; 47 public int min_num_tracks, max_num_tracks; 48 public double recorded_percent; 49 public List<TrackInfo> track_info = new List<TrackInfo>(); 50 public string most_popular_user_track = string.Empty; 51 52 public TimelineEventInfo(TimelineSceneInfo sceneInfo) 53 { 54 num_timelines = sceneInfo.uniqueDirectors.Count; 55 min_duration = sceneInfo.minDuration; 56 max_duration = sceneInfo.maxDuration; 57 min_num_tracks = sceneInfo.minNumTracks; 58 max_num_tracks = sceneInfo.maxNumTracks; 59 recorded_percent = Math.Round(100.0 * sceneInfo.numRecorded / sceneInfo.numTracks, 1); 60 61 foreach (KeyValuePair<string, int> kv in sceneInfo.trackCount.Where(x => x.Value > 0)) 62 { 63 track_info.Add(new TrackInfo() 64 { 65 name = kv.Key, 66 percent = Math.Round(100.0 * kv.Value / sceneInfo.numTracks, 1) 67 }); 68 } 69 70 if (sceneInfo.userTrackTypesCount.Any()) 71 { 72 most_popular_user_track = sceneInfo.userTrackTypesCount 73 .First(x => x.Value == sceneInfo.userTrackTypesCount.Values.Max()).Key; 74 } 75 } 76 77 public static bool IsUserType(Type t) 78 { 79 string nameSpace = t.Namespace; 80 return string.IsNullOrEmpty(nameSpace) || !nameSpace.StartsWith("UnityEngine.Timeline"); 81 } 82 } 83 84 85 static class TimelineAnalytics 86 { 87 static TimelineSceneInfo _timelineSceneInfo = new TimelineSceneInfo(); 88 89 class TimelineAnalyticsPreProcess : IPreprocessBuildWithReport 90 { 91 public int callbackOrder { get { return 0; } } 92 public void OnPreprocessBuild(BuildReport report) 93 { 94 _timelineSceneInfo = new TimelineSceneInfo(); 95 } 96 } 97 98 class TimelineAnalyticsProcess : IProcessSceneWithReport 99 { 100 public int callbackOrder 101 { 102 get { return 0; } 103 } 104 105 public void OnProcessScene(Scene scene, BuildReport report) 106 { 107 PlayableDirector[] directorsInScene = GetAllDirectorsInScene(); 108 IEnumerable<TimelineAsset> timelines = directorsInScene.Select(pd => pd.playableAsset).OfType<TimelineAsset>().Distinct(); 109 110 foreach (var timeline in timelines) 111 { 112 if (_timelineSceneInfo.uniqueDirectors.Add(timeline)) 113 { 114 _timelineSceneInfo.numTracks += timeline.flattenedTracks.Count(); 115 _timelineSceneInfo.minDuration = Math.Min(_timelineSceneInfo.minDuration, (int)(timeline.duration * 1000)); 116 _timelineSceneInfo.maxDuration = Math.Max(_timelineSceneInfo.maxDuration, (int)(timeline.duration * 1000)); 117 _timelineSceneInfo.minNumTracks = Math.Min(_timelineSceneInfo.minNumTracks, timeline.flattenedTracks.Count()); 118 _timelineSceneInfo.maxNumTracks = Math.Max(_timelineSceneInfo.maxNumTracks, timeline.flattenedTracks.Count()); 119 120 foreach (var track in timeline.flattenedTracks) 121 { 122 string key = track.GetType().Name; 123 if (_timelineSceneInfo.trackCount.ContainsKey(key)) 124 { 125 _timelineSceneInfo.trackCount[key]++; 126 } 127 else 128 { 129 if (TimelineEventInfo.IsUserType(track.GetType())) 130 { 131 _timelineSceneInfo.trackCount["UserType"]++; 132 if (_timelineSceneInfo.userTrackTypesCount.ContainsKey(key)) 133 _timelineSceneInfo.userTrackTypesCount[key]++; 134 else 135 _timelineSceneInfo.userTrackTypesCount[key] = 1; 136 } 137 else 138 _timelineSceneInfo.trackCount["Other"]++; 139 } 140 141 if (track.clips.Any(x => x.recordable)) 142 _timelineSceneInfo.numRecorded++; 143 else 144 { 145 var animationTrack = track as AnimationTrack; 146 if (animationTrack != null) 147 { 148 if (animationTrack.CanConvertToClipMode()) 149 _timelineSceneInfo.numRecorded++; 150 } 151 } 152 } 153 } 154 } 155 } 156 } 157 158 static PlayableDirector[] GetAllDirectorsInScene() 159 { 160#if UNITY_2023_1_OR_NEWER 161 return UnityEngine.Object.FindObjectsByType<PlayableDirector>(UnityEngine.FindObjectsSortMode.None); 162#else 163 return UnityEngine.Object.FindObjectsOfType<PlayableDirector>(); 164#endif 165 } 166 167 class TimelineAnalyticsPostProcess : IPostprocessBuildWithReport 168 { 169 public int callbackOrder { get { return 0; } } 170 public void OnPostprocessBuild(BuildReport report) 171 { 172 if (_timelineSceneInfo.uniqueDirectors.Count > 0) 173 { 174 var timelineEvent = new TimelineEventInfo(_timelineSceneInfo); 175 EditorAnalytics.SendEventTimelineInfo(timelineEvent); 176 } 177 } 178 } 179 } 180}