暫無描述
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.

PostProcessDataAnalytics.cs 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEditor.Build;
  4. using UnityEditor.Build.Reporting;
  5. using UnityEngine;
  6. using UnityEngine.Analytics;
  7. using UnityEngine.Rendering;
  8. using UnityEngine.Rendering.Universal;
  9. using Object = UnityEngine.Object;
  10. namespace UnityEditor.Rendering.Universal
  11. {
  12. class PostProcessDataAnalytics : IPostprocessBuildWithReport
  13. {
  14. const int k_MaxEventsPerHour = 1000;
  15. const int k_MaxNumberOfElements = 1000;
  16. const string k_VendorKey = "unity.universal";
  17. const string k_EventName = "uURPPostProcessAsset";
  18. // SCHEMA: com.unity3d.data.schemas.editor.analytics.uURPPostProcessAsset_v1
  19. // TAXONOMY : editor.analytics.uURPPostProcessAsset.v1
  20. [AnalyticInfo(eventName: k_EventName, vendorKey: k_VendorKey, maxEventsPerHour: k_MaxEventsPerHour, maxNumberOfElements: k_MaxNumberOfElements)]
  21. public class Analytic : IAnalytic
  22. {
  23. [Serializable]
  24. public struct AnalyticsData : IAnalytic.IData
  25. {
  26. public string property;
  27. public string usage;
  28. }
  29. public bool TryGatherData(out IAnalytic.IData data, out Exception error)
  30. {
  31. data = null;
  32. using (ListPool<PostProcessData>.Get(out var tmp))
  33. {
  34. if (TryGatherPostProcessDataIncludedInBuild(tmp))
  35. data = GatherDataToBeSent(ExtractData(tmp));
  36. }
  37. error = null;
  38. return true;
  39. }
  40. [Serializable]
  41. public class PropertyToGUIDs
  42. {
  43. public string propertyName;
  44. public string defaultGUID;
  45. public List<string> usedGUIDs = new();
  46. }
  47. static bool TryGatherPostProcessDataIncludedInBuild(List<PostProcessData> tmp)
  48. {
  49. foreach (var renderPipelineAsset in URPBuildData.instance.renderPipelineAssets)
  50. {
  51. foreach (var rendererData in renderPipelineAsset.m_RendererDataList)
  52. {
  53. PostProcessData postProcessData = rendererData switch
  54. {
  55. Renderer2DData renderer2DData => renderer2DData.postProcessData,
  56. UniversalRendererData universalRendererData => universalRendererData.postProcessData,
  57. _ => null
  58. };
  59. if (postProcessData != null)
  60. tmp.Add(postProcessData);
  61. }
  62. }
  63. return tmp.Count != 0;
  64. }
  65. static List<(string property, string guid)> GetPropertyGUIDs(object instance)
  66. {
  67. List<(string property, string guid)> output = new();
  68. foreach (var field in instance.GetType().GetSerializableFields())
  69. {
  70. var assetPath = AssetDatabase.GetAssetPath(field.GetValue(instance) as Object);
  71. var guid = AssetDatabase.GUIDFromAssetPath(assetPath).ToString();
  72. output.Add((field.Name, guid));
  73. }
  74. return output;
  75. }
  76. public static PropertyToGUIDs[] ExtractData(List<PostProcessData> postProcessDatas)
  77. {
  78. Dictionary<string, PropertyToGUIDs> output = CreateDictionaryWithDefaults();
  79. AddUsages(postProcessDatas, output);
  80. return ToPropertyToGUIDsArray(output);
  81. }
  82. private static Dictionary<string, PropertyToGUIDs> CreateDictionaryWithDefaults()
  83. {
  84. var defaultPostProcessData = ScriptableObject.CreateInstance<PostProcessData>();
  85. ResourceReloader.ReloadAllNullIn(defaultPostProcessData, UniversalRenderPipelineAsset.packagePath);
  86. Dictionary<string, PropertyToGUIDs> output = new();
  87. void AddDefaultsToDictionary(Dictionary<string, PropertyToGUIDs> dictionary,
  88. List<(string property, string guid)> list)
  89. {
  90. foreach (var item in list)
  91. dictionary.Add(item.property,
  92. new PropertyToGUIDs() { propertyName = item.property, defaultGUID = item.guid });
  93. }
  94. AddDefaultsToDictionary(output, GetPropertyGUIDs(defaultPostProcessData.shaders));
  95. AddDefaultsToDictionary(output, GetPropertyGUIDs(defaultPostProcessData.textures));
  96. ScriptableObject.DestroyImmediate(defaultPostProcessData);
  97. return output;
  98. }
  99. private static void AddUsages(List<PostProcessData> postProcessDatas, Dictionary<string, PropertyToGUIDs> output)
  100. {
  101. void AddUsageToDictionary(Dictionary<string, PropertyToGUIDs> dictionary, List<(string property, string guid)> list)
  102. {
  103. foreach (var item in list)
  104. dictionary[item.property].usedGUIDs.Add(item.guid);
  105. }
  106. foreach (var ppData in postProcessDatas)
  107. {
  108. AddUsageToDictionary(output, GetPropertyGUIDs(ppData.shaders));
  109. AddUsageToDictionary(output, GetPropertyGUIDs(ppData.textures));
  110. }
  111. }
  112. private static PropertyToGUIDs[] ToPropertyToGUIDsArray(Dictionary<string, PropertyToGUIDs> output)
  113. {
  114. PropertyToGUIDs[] valuesArray = new PropertyToGUIDs[output.Count];
  115. int index = 0;
  116. foreach (var value in output.Values)
  117. {
  118. valuesArray[index] = value;
  119. index++;
  120. }
  121. return valuesArray;
  122. }
  123. public static IAnalytic.DataList<AnalyticsData> GatherDataToBeSent(PropertyToGUIDs[] dictionary)
  124. {
  125. using (ListPool<AnalyticsData>.Get(out var tmp))
  126. {
  127. var uniques = new HashSet<string>();
  128. foreach (var i in dictionary)
  129. {
  130. foreach (var u in i.usedGUIDs)
  131. uniques.Add(u);
  132. switch (uniques.Count)
  133. {
  134. case 0:
  135. continue;
  136. case 1:
  137. if (!uniques.Contains(i.defaultGUID))
  138. {
  139. tmp.Add(new AnalyticsData()
  140. {
  141. property = i.propertyName,
  142. usage = Usage.ModifiedForTheProject.ToString()
  143. });
  144. }
  145. break;
  146. default:
  147. tmp.Add(new AnalyticsData()
  148. {
  149. property = i.propertyName,
  150. usage = Usage.ModifiedForEachQualityLevel.ToString()
  151. });
  152. break;
  153. }
  154. uniques.Clear();
  155. }
  156. return new IAnalytic.DataList<AnalyticsData>(tmp.ToArray());
  157. }
  158. }
  159. public enum Usage
  160. {
  161. ModifiedForTheProject,
  162. ModifiedForEachQualityLevel,
  163. }
  164. }
  165. static void SendUniversalEvent()
  166. {
  167. //The event shouldn't be able to report if this is disabled but if we know we're not going to report
  168. //Lets early out and not waste time gathering all the data
  169. if (!EditorAnalytics.enabled)
  170. return;
  171. Analytic analytic = new Analytic();
  172. EditorAnalytics.SendAnalytic(analytic);
  173. }
  174. public int callbackOrder { get; }
  175. public void OnPostprocessBuild(BuildReport report)
  176. {
  177. SendUniversalEvent();
  178. }
  179. }
  180. }