188 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			188 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| //#define ANALYTICS_DEBUG
 | |
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Diagnostics;
 | |
| using System.Linq;
 | |
| using System.Text;
 | |
| using UnityEngine.Analytics;
 | |
| using UnityEngine.Timeline;
 | |
| 
 | |
| namespace UnityEditor.Timeline
 | |
| {
 | |
|     class TimelineWindowAnalytics
 | |
|     {
 | |
|         const string vendorKey = "unity.timeline";
 | |
|         const string eventName = "timeline_editor_info";
 | |
|         const int version = 2;
 | |
|         const int maxEventsPerHour = 1000;
 | |
|         const int maxNumberOfElements = 1000;
 | |
| 
 | |
|         [Serializable]
 | |
|         internal struct timeline_asset_stats
 | |
| #if UNITY_2023_2_OR_NEWER
 | |
|             : IAnalytic.IData
 | |
| #endif
 | |
|         {
 | |
|             public string asset_guid;
 | |
|             public double duration;
 | |
|             public double frame_rate;
 | |
|             public List<track_asset_stats> track_stats;
 | |
|             public double mix_samples_count, ripple_samples_count, replace_samples_count;
 | |
|             public string display_format;
 | |
|         }
 | |
| 
 | |
|         [Serializable]
 | |
|         internal struct track_asset_stats
 | |
|         {
 | |
|             public string track_type;
 | |
|             public int clip_count;
 | |
|             public int marker_count;
 | |
|         }
 | |
| 
 | |
|         class WindowAnalyticsStats
 | |
|         {
 | |
|             internal int[] editModeSamples = new int[3]; // EditModes
 | |
|         }
 | |
| 
 | |
| #if UNITY_2023_2_OR_NEWER
 | |
|         [AnalyticInfo(
 | |
|             eventName: eventName,
 | |
|             vendorKey: vendorKey,
 | |
|             version: version,
 | |
|             maxEventsPerHour: maxEventsPerHour,
 | |
|             maxNumberOfElements: maxNumberOfElements)]
 | |
|         class TimelineWindowAnalyticsEvent : IAnalytic
 | |
|         {
 | |
|             public timeline_asset_stats timelineStats { get; }
 | |
|             bool m_CanSendData;
 | |
| 
 | |
|             public TimelineWindowAnalyticsEvent()
 | |
|             {
 | |
|                 m_CanSendData = GenerateTimelineAssetStats(out timeline_asset_stats data);
 | |
|                 timelineStats = data;
 | |
|             }
 | |
| 
 | |
|             public void Send()
 | |
|             {
 | |
|                 if (m_CanSendData)
 | |
|                     EditorAnalytics.SendAnalytic(this);
 | |
|             }
 | |
| 
 | |
|             bool IAnalytic.TryGatherData(out IAnalytic.IData data, out Exception error)
 | |
|             {
 | |
|                 error = null;
 | |
|                 data = timelineStats;
 | |
|                 return true;
 | |
|             }
 | |
|         }
 | |
| #endif
 | |
| 
 | |
|         static WindowAnalyticsStats analyticsStats = new WindowAnalyticsStats();
 | |
| 
 | |
|         public void SendPlayEvent(bool start)
 | |
|         {
 | |
|             if (!start || !EditorAnalytics.enabled)
 | |
|                 return;
 | |
| 
 | |
| #if UNITY_2023_2_OR_NEWER
 | |
|             var analyticsEvent = new TimelineWindowAnalyticsEvent();
 | |
|             LogAnalyticsData(analyticsEvent.timelineStats);
 | |
|             analyticsEvent.Send();
 | |
| #else
 | |
|             EditorAnalytics.RegisterEventWithLimit(eventName, maxEventsPerHour, maxNumberOfElements, vendorKey, version);
 | |
|             var ret = GenerateTimelineAssetStats(out var data);
 | |
|             if (!ret)
 | |
|                 return;
 | |
|             LogAnalyticsData(data);
 | |
|             EditorAnalytics.SendEventWithLimit(eventName, data, version);
 | |
| #endif
 | |
|             SendAfterSequenceChangeEvent();
 | |
|         }
 | |
| 
 | |
|         public void SendAfterSequenceChangeEvent()
 | |
|         {
 | |
|             analyticsStats = new WindowAnalyticsStats(); // Wipe Window Stats
 | |
|         }
 | |
| 
 | |
|         public void SendManipulationEndedEvent()
 | |
|         {
 | |
|             analyticsStats.editModeSamples[(int)EditMode.editType]++;
 | |
|         }
 | |
| 
 | |
|         internal static bool GenerateTimelineAssetStats(out timeline_asset_stats data)
 | |
|         {
 | |
|             var timeline = TimelineEditor.inspectedAsset;
 | |
|             if (timeline == null ||
 | |
|                 !AssetDatabase.TryGetGUIDAndLocalFileIdentifier(timeline, out var guid, out long _))
 | |
|             {
 | |
|                 data = new timeline_asset_stats();
 | |
|                 return false;
 | |
|             }
 | |
| 
 | |
|             data = new timeline_asset_stats
 | |
|             {
 | |
|                 asset_guid = guid,
 | |
|                 duration = timeline.duration,
 | |
|                 frame_rate = timeline.editorSettings.frameRate,
 | |
|                 track_stats = GetTrackAssetStats(timeline),
 | |
|                 display_format = TimelinePreferences.instance.timeFormat.ConvertToString(),
 | |
|                 mix_samples_count = analyticsStats.editModeSamples[(int)EditMode.EditType.Mix],
 | |
|                 ripple_samples_count = analyticsStats.editModeSamples[(int)EditMode.EditType.Ripple],
 | |
|                 replace_samples_count = analyticsStats.editModeSamples[(int)EditMode.EditType.Replace],
 | |
|             };
 | |
| 
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         static List<track_asset_stats> GetTrackAssetStats(TimelineAsset timeline)
 | |
|         {
 | |
|             var ret = new List<track_asset_stats>();
 | |
|             foreach (var track in timeline.flattenedTracks)
 | |
|             {
 | |
|                 ret.Add(new track_asset_stats
 | |
|                 {
 | |
|                     track_type = track.GetType().FullName,
 | |
|                     clip_count = track.GetClips().Count(),
 | |
|                     marker_count = track.GetMarkers().Count()
 | |
|                 }
 | |
|                 );
 | |
|             }
 | |
|             return ret;
 | |
|         }
 | |
| 
 | |
|         [Conditional("ANALYTICS_DEBUG")]
 | |
|         static void LogAnalyticsData(timeline_asset_stats data)
 | |
|         {
 | |
|             UnityEngine.Debug.Log(UnityEngine.JsonUtility.ToJson(data, true));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     static class ConversionUtilities
 | |
|     {
 | |
|         internal static string ConvertToString<T>(this T e) where T : Enum
 | |
|         {
 | |
|             return Enum.GetName(typeof(T), e).ToSnakeCase();
 | |
|         }
 | |
| 
 | |
|         static string ToSnakeCase(this string str)
 | |
|         {
 | |
|             var sb = new StringBuilder();
 | |
|             for (var i = 0; i < str.Length - 1; ++i)
 | |
|             {
 | |
|                 var ch = str[i];
 | |
|                 var nCh = str[i + 1];
 | |
|                 if (char.IsUpper(ch) && char.IsLower(nCh))
 | |
|                 {
 | |
|                     sb.Append("_");
 | |
|                 }
 | |
| 
 | |
|                 sb.Append(ch.ToString().ToLower());
 | |
|             }
 | |
| 
 | |
|             sb.Append(str[str.Length - 1].ToString().ToLower());
 | |
| 
 | |
|             return sb.ToString().TrimStart('_');
 | |
|         }
 | |
|     }
 | |
| }
 |