暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TimelineWindowAnalytics.cs 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. //#define ANALYTICS_DEBUG
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Linq;
  6. using System.Text;
  7. using UnityEngine.Analytics;
  8. using UnityEngine.Timeline;
  9. namespace UnityEditor.Timeline
  10. {
  11. class TimelineWindowAnalytics
  12. {
  13. const string vendorKey = "unity.timeline";
  14. const string eventName = "timeline_editor_info";
  15. const int version = 2;
  16. const int maxEventsPerHour = 1000;
  17. const int maxNumberOfElements = 1000;
  18. [Serializable]
  19. internal struct timeline_asset_stats
  20. #if UNITY_2023_2_OR_NEWER
  21. : IAnalytic.IData
  22. #endif
  23. {
  24. public string asset_guid;
  25. public double duration;
  26. public double frame_rate;
  27. public List<track_asset_stats> track_stats;
  28. public double mix_samples_count, ripple_samples_count, replace_samples_count;
  29. public string display_format;
  30. }
  31. [Serializable]
  32. internal struct track_asset_stats
  33. {
  34. public string track_type;
  35. public int clip_count;
  36. public int marker_count;
  37. }
  38. class WindowAnalyticsStats
  39. {
  40. internal int[] editModeSamples = new int[3]; // EditModes
  41. }
  42. #if UNITY_2023_2_OR_NEWER
  43. [AnalyticInfo(
  44. eventName: eventName,
  45. vendorKey: vendorKey,
  46. version: version,
  47. maxEventsPerHour: maxEventsPerHour,
  48. maxNumberOfElements: maxNumberOfElements)]
  49. class TimelineWindowAnalyticsEvent : IAnalytic
  50. {
  51. public timeline_asset_stats timelineStats { get; }
  52. bool m_CanSendData;
  53. public TimelineWindowAnalyticsEvent()
  54. {
  55. m_CanSendData = GenerateTimelineAssetStats(out timeline_asset_stats data);
  56. timelineStats = data;
  57. }
  58. public void Send()
  59. {
  60. if (m_CanSendData)
  61. EditorAnalytics.SendAnalytic(this);
  62. }
  63. bool IAnalytic.TryGatherData(out IAnalytic.IData data, out Exception error)
  64. {
  65. error = null;
  66. data = timelineStats;
  67. return true;
  68. }
  69. }
  70. #endif
  71. static WindowAnalyticsStats analyticsStats = new WindowAnalyticsStats();
  72. public void SendPlayEvent(bool start)
  73. {
  74. if (!start || !EditorAnalytics.enabled)
  75. return;
  76. #if UNITY_2023_2_OR_NEWER
  77. var analyticsEvent = new TimelineWindowAnalyticsEvent();
  78. LogAnalyticsData(analyticsEvent.timelineStats);
  79. analyticsEvent.Send();
  80. #else
  81. EditorAnalytics.RegisterEventWithLimit(eventName, maxEventsPerHour, maxNumberOfElements, vendorKey, version);
  82. var ret = GenerateTimelineAssetStats(out var data);
  83. if (!ret)
  84. return;
  85. LogAnalyticsData(data);
  86. EditorAnalytics.SendEventWithLimit(eventName, data, version);
  87. #endif
  88. SendAfterSequenceChangeEvent();
  89. }
  90. public void SendAfterSequenceChangeEvent()
  91. {
  92. analyticsStats = new WindowAnalyticsStats(); // Wipe Window Stats
  93. }
  94. public void SendManipulationEndedEvent()
  95. {
  96. analyticsStats.editModeSamples[(int)EditMode.editType]++;
  97. }
  98. internal static bool GenerateTimelineAssetStats(out timeline_asset_stats data)
  99. {
  100. var timeline = TimelineEditor.inspectedAsset;
  101. if (timeline == null ||
  102. !AssetDatabase.TryGetGUIDAndLocalFileIdentifier(timeline, out var guid, out long _))
  103. {
  104. data = new timeline_asset_stats();
  105. return false;
  106. }
  107. data = new timeline_asset_stats
  108. {
  109. asset_guid = guid,
  110. duration = timeline.duration,
  111. frame_rate = timeline.editorSettings.frameRate,
  112. track_stats = GetTrackAssetStats(timeline),
  113. display_format = TimelinePreferences.instance.timeFormat.ConvertToString(),
  114. mix_samples_count = analyticsStats.editModeSamples[(int)EditMode.EditType.Mix],
  115. ripple_samples_count = analyticsStats.editModeSamples[(int)EditMode.EditType.Ripple],
  116. replace_samples_count = analyticsStats.editModeSamples[(int)EditMode.EditType.Replace],
  117. };
  118. return true;
  119. }
  120. static List<track_asset_stats> GetTrackAssetStats(TimelineAsset timeline)
  121. {
  122. var ret = new List<track_asset_stats>();
  123. foreach (var track in timeline.flattenedTracks)
  124. {
  125. ret.Add(new track_asset_stats
  126. {
  127. track_type = track.GetType().FullName,
  128. clip_count = track.GetClips().Count(),
  129. marker_count = track.GetMarkers().Count()
  130. }
  131. );
  132. }
  133. return ret;
  134. }
  135. [Conditional("ANALYTICS_DEBUG")]
  136. static void LogAnalyticsData(timeline_asset_stats data)
  137. {
  138. UnityEngine.Debug.Log(UnityEngine.JsonUtility.ToJson(data, true));
  139. }
  140. }
  141. static class ConversionUtilities
  142. {
  143. internal static string ConvertToString<T>(this T e) where T : Enum
  144. {
  145. return Enum.GetName(typeof(T), e).ToSnakeCase();
  146. }
  147. static string ToSnakeCase(this string str)
  148. {
  149. var sb = new StringBuilder();
  150. for (var i = 0; i < str.Length - 1; ++i)
  151. {
  152. var ch = str[i];
  153. var nCh = str[i + 1];
  154. if (char.IsUpper(ch) && char.IsLower(nCh))
  155. {
  156. sb.Append("_");
  157. }
  158. sb.Append(ch.ToString().ToLower());
  159. }
  160. sb.Append(str[str.Length - 1].ToString().ToLower());
  161. return sb.ToString().TrimStart('_');
  162. }
  163. }
  164. }