This commit is contained in:
2024-09-20 20:30:10 +02:00
commit 4fabf1a6fd
29169 changed files with 1706941 additions and 0 deletions

View File

@@ -0,0 +1,282 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using UnityEngine;
using UnityEngine.Analytics;
using UnityEngine.Pool;
namespace UnityEditor.Rendering
{
/// <summary>
/// Set of utilities for analytics
/// </summary>
public static class AnalyticsUtils
{
const string k_VendorKey = "unity.srp";
internal static bool TryRegisterEvent(string eventName, int version = 1, int maxEventPerHour = 100, int maxNumberOfElements = 1000)
{
if (!EditorAnalytics.enabled) return false;
if (EditorAnalytics.RegisterEventWithLimit(eventName, maxEventPerHour, maxNumberOfElements, k_VendorKey, version) != AnalyticsResult.Ok) return false;
return true;
}
internal static void SendData<T>(T data, string eventName, int version)
{
EditorAnalytics.SendEventWithLimit(eventName, data, version);
}
internal static IEnumerable<FieldInfo> GetSerializableFields(this Type type, bool removeObsolete = false)
{
var members = type.GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
if (type.BaseType != null && type.BaseType != typeof(object))
{
foreach (FieldInfo field in type.BaseType.GetSerializableFields())
{
yield return field;
}
}
foreach (var member in members)
{
if (member.MemberType != MemberTypes.Field && member.MemberType != MemberTypes.Property)
{
continue;
}
if (member.DeclaringType != type || member is not FieldInfo field)
{
continue;
}
if (removeObsolete && member.GetCustomAttribute<ObsoleteAttribute>() != null)
continue;
if (field.IsPublic)
{
if (member.GetCustomAttribute<NonSerializedAttribute>() != null)
continue;
yield return field;
}
else
{
if (member.GetCustomAttribute<SerializeField>() != null)
yield return field;
}
}
}
static bool AreArraysDifferent(IList a, IList b)
{
if ((a == null) && (b == null))
return false;
if ((a == null) ^ (b == null))
return true;
if (a.Count != b.Count)
return true;
for (int i = 0; i < a.Count; i++)
{
if (!a[i].Equals(b[i]))
return true;
}
return false;
}
static string DumpValues(this IList list)
{
using (ListPool<string>.Get(out var tempList))
{
for (int i = 0; i < list.Count; i++)
{
tempList.Add(list[i].ToString());
}
var arrayValues = string.Join(",", tempList);
return $"[{arrayValues}]";
}
}
static Dictionary<string, string> DumpValues(Type type, object current)
{
var diff = new Dictionary<string, string>();
foreach (var field in type.GetSerializableFields(removeObsolete: true))
{
var t = field.FieldType;
try
{
if (typeof(ScriptableObject).IsAssignableFrom(t))
continue;
var valueCurrent = current != null ? field.GetValue(current) : null;
if (t == typeof(string))
{
var stringCurrent = (string)valueCurrent;
diff[field.Name] = stringCurrent;
}
else if (t.IsPrimitive || t.IsEnum)
{
diff[field.Name] = valueCurrent.ToString();
}
else if (t.IsArray && valueCurrent is IList valueCurrentList)
{
diff[field.Name] = valueCurrentList.DumpValues();
}
else if (t.IsClass || t.IsValueType)
{
if (valueCurrent is IEnumerable ea)
continue; // List<T> not supported
var subDiff = DumpValues(t, valueCurrent);
foreach (var d in subDiff)
{
diff[field.Name + "." + d.Key] = d.Value;
}
}
}
catch (Exception ex)
{
Debug.LogError($"Exception found while parsing {field}, {ex}");
}
}
return diff;
}
static Dictionary<string, string> GetDiffAsDictionary(Type type, object current, object defaults)
{
var diff = new Dictionary<string, string>();
foreach (var field in type.GetSerializableFields())
{
var t = field.FieldType;
try
{
if (t.GetCustomAttribute<ObsoleteAttribute>() != null || typeof(ScriptableObject).IsAssignableFrom(t))
continue;
var valueCurrent = current != null ? field.GetValue(current) : null;
var valueDefault = defaults != null ? field.GetValue(defaults) : null;
if (t == typeof(string))
{
var stringCurrent = (string)valueCurrent;
var stringDefault = (string)valueDefault;
if (stringCurrent != stringDefault)
{
diff[field.Name] = stringCurrent;
}
}
else if (t.IsPrimitive || t.IsEnum)
{
if (!valueCurrent.Equals(valueDefault))
diff[field.Name] = valueCurrent.ToString();
}
else if (t.IsArray && valueCurrent is IList valueCurrentList)
{
if (AreArraysDifferent(valueCurrentList, valueDefault as IList))
diff[field.Name] = valueCurrentList.DumpValues();
}
else if (t.IsClass || t.IsValueType)
{
if (valueCurrent is IEnumerable ea)
continue; // List<T> not supported
var subDiff = GetDiffAsDictionary(t, valueCurrent, valueDefault);
foreach (var d in subDiff)
{
diff[field.Name + "." + d.Key] = d.Value;
}
}
}
catch (Exception ex)
{
Debug.LogError($"Exception found while parsing {field}, {ex}");
}
}
return diff;
}
static string[] ToStringArray(Dictionary<string, string> diff)
{
var changedSettings = new string[diff.Count];
int i = 0;
foreach (var d in diff)
changedSettings[i++] = $@"{{""{d.Key}"":""{d.Value}""}}";
return changedSettings;
}
/// <summary>
/// Obtains the Serialized fields and values in form of nested columns for BigQuery
/// https://cloud.google.com/bigquery/docs/nested-repeated
/// </summary>
/// <typeparam name="T">The given type</typeparam>
/// <param name="current">The current object to obtain the fields and values.</param>
/// <param name="compareAndSimplifyWithDefault">If a comparison against the default value must be done.</param>
/// <returns>The nested columns in form of {key.nestedKey : value} </returns>
/// <exception cref="ArgumentNullException"></exception>
public static string[] ToNestedColumn<T>([DisallowNull] this T current, bool compareAndSimplifyWithDefault = false)
where T : new()
{
if (current == null)
throw new ArgumentNullException(nameof(current));
var type = current.GetType();
Dictionary<string, string> diff;
if (compareAndSimplifyWithDefault)
{
if (typeof(UnityEngine.Object).IsAssignableFrom(typeof(T)))
{
var instance = ScriptableObject.CreateInstance(type);
diff = GetDiffAsDictionary(type, current, instance);
ScriptableObject.DestroyImmediate(instance);
}
else
{
diff = GetDiffAsDictionary(type, current, new T());
}
}
else
{
diff = DumpValues(type, current);
}
return ToStringArray(diff);
}
/// <summary>
/// Obtains the Serialized fields and values in form of nested columns for BigQuery
/// https://cloud.google.com/bigquery/docs/nested-repeated
/// </summary>
/// <typeparam name="T">The given type</typeparam>
/// <param name="current">The current object to obtain the fields and values.</param>
/// <param name="defaultObject">The default object</param>
/// <param name="compareAndSimplifyWithDefault">If a comparison against the default value must be done.</param>
/// <returns>The nested columns in form of {key.nestedKey : value} </returns>
/// <exception cref="ArgumentNullException"></exception>
public static string[] ToNestedColumnWithDefault<T>([DisallowNull] this T current, [DisallowNull] T defaultObject, bool compareAndSimplifyWithDefault = false)
{
if (current == null)
throw new ArgumentNullException(nameof(current));
var type = current.GetType();
Dictionary<string, string> diff = (compareAndSimplifyWithDefault) ?
GetDiffAsDictionary(type, current, defaultObject) : DumpValues(type, current);
return ToStringArray(diff);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0bbdae02753ac26469071b3d5c0fe9d9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,72 @@
using JetBrains.Annotations;
using System.Diagnostics.CodeAnalysis;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;
using UnityEngine.Analytics;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering.Analytics
{
internal class BuildTargetAnalytic : IPostprocessBuildWithReport
{
public int callbackOrder => int.MaxValue;
const int k_MaxEventsPerHour = 10;
const int k_MaxNumberOfElements = 1000;
const string k_VendorKey = "unity.srp";
[System.Diagnostics.DebuggerDisplay("{render_pipeline_asset_type} - {quality_levels}/{total_quality_levels_on_project}")]
internal struct BuildTargetAnalyticData
{
internal const string k_EventName = "uBuildTargetAnalytic";
// Naming convention for analytics data
public string build_target;
public string render_pipeline_asset_type;
public int quality_levels;
public int total_quality_levels_on_project;
};
void IPostprocessBuildWithReport.OnPostprocessBuild(BuildReport _)
{
if (!EditorAnalytics.enabled || EditorAnalytics.RegisterEventWithLimit(BuildTargetAnalyticData.k_EventName, k_MaxEventsPerHour, k_MaxNumberOfElements, k_VendorKey) != AnalyticsResult.Ok)
return;
if (!TryGatherData(out var data, out var warning))
Debug.Log(warning);
EditorAnalytics.SendEventWithLimit(BuildTargetAnalyticData.k_EventName, data);
}
[MustUseReturnValue]
static bool TryGatherData([NotNullWhen(true)] out BuildTargetAnalyticData data, [NotNullWhen(false)] out string warning)
{
var activeBuildTarget = EditorUserBuildSettings.activeBuildTarget;
var activeBuildTargetGroup = BuildPipeline.GetBuildTargetGroup(activeBuildTarget);
var activeBuildTargetGroupName = activeBuildTargetGroup.ToString();
warning = string.Empty;
var assetType = GraphicsSettings.currentRenderPipeline == null ? "Built-In Render Pipeline" : GraphicsSettings.currentRenderPipeline.GetType().ToString();
data = new BuildTargetAnalyticData()
{
build_target = activeBuildTarget.ToString(),
quality_levels = QualitySettings.GetActiveQualityLevelsForPlatformCount(activeBuildTargetGroupName),
render_pipeline_asset_type = assetType,
total_quality_levels_on_project = QualitySettings.count
};
return true;
}
[MenuItem("internal:Edit/Rendering/Analytics/Send BuildTargetAnalytic ", priority = 0)]
static void SendAnalyitic()
{
if (!TryGatherData(out var data, out var warning))
Debug.Log(warning);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9f249a7110f8dd14ca061023fb8aa6e5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
using System.Diagnostics;
using UnityEngine.Analytics;
namespace UnityEditor.Rendering.Analytics
{
// schema = com.unity3d.data.schemas.editor.analytics.uDebugManagerWidgetUsedAnalytic_v1
// taxonomy = editor.analytics.uDebugManagerWidgetUsedAnalytic.v1
internal class DebugManagerWidgetUsedAnalytic
{
const int k_MaxEventsPerHour = 1000;
const int k_MaxNumberOfElements = 1000;
const string k_VendorKey = "unity.srp";
[DebuggerDisplay("{query_path} - {value}")]
class Data
{
internal const string k_EventName = "uDebugManagerWidgetUsedAnalytic";
// Naming convention for analytics data
public string query_path;
public string value;
}
public static void Send(string path, object value)
{
if (EditorAnalytics.enabled &&
EditorAnalytics.RegisterEventWithLimit(Data.k_EventName, k_MaxEventsPerHour, k_MaxNumberOfElements, k_VendorKey) == AnalyticsResult.Ok)
{
using (UnityEngine.Pool.GenericPool<Data>.Get(out var data))
{
data.query_path = path;
data.value = value.ToString();
EditorAnalytics.SendEventWithLimit(Data.k_EventName, data);
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f3400ad1efb6cc346b10e6ff7586b933
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,78 @@
using System;
using System.Diagnostics;
using System.Linq;
using UnityEngine.Analytics;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering.Analytics
{
// schema = com.unity3d.data.schemas.editor.analytics.uDebugManagerWindowLifetimeAnalytic_v1
// taxonomy = editor.analytics.uDebugManagerWindowLifetimeAnalytic.v1
internal class DebugManagerWindowLifetimeAnalytic
{
const int k_MaxEventsPerHour = 10;
const int k_MaxNumberOfElements = 1000;
const string k_VendorKey = "unity.srp";
private static DateTime?[] timeStamps = new DateTime?[2] { null, null};
[InitializeOnLoadMethod]
static void SubscribeToDebugManagerOpenCloseWindows()
{
DebugManager.windowStateChanged += OnWindowStateChanged;
AssemblyReloadEvents.beforeAssemblyReload += OnBeforeAssemblyReload;
}
private static void OnBeforeAssemblyReload()
{
AssemblyReloadEvents.beforeAssemblyReload -= OnBeforeAssemblyReload;
DebugManager.windowStateChanged -= OnWindowStateChanged;
}
private static void OnWindowStateChanged(DebugManager.UIMode windowMode, bool open)
{
try
{
if (!timeStamps[(int)windowMode].HasValue)
{
timeStamps[(int)windowMode] = DateTime.Now;
}
else
{
Send(windowMode, timeStamps[(int)windowMode].Value);
timeStamps[(int)windowMode] = null;
}
}
catch
{
// ignored, do not let analytics throw an error
}
}
[DebuggerDisplay("{window_mode} - {seconds_opened}")]
class Data
{
internal const string k_EventName = "uDebugManagerWindowLifetimeAnalytic";
// Naming convention for analytics data
public string window_mode;
public int seconds_opened;
}
static void Send(DebugManager.UIMode windowMode, DateTime start)
{
var elapsed = DateTime.Now - start;
if (EditorAnalytics.enabled &&
EditorAnalytics.RegisterEventWithLimit(Data.k_EventName, k_MaxEventsPerHour, k_MaxNumberOfElements, k_VendorKey) == AnalyticsResult.Ok)
{
using (UnityEngine.Pool.GenericPool<Data>.Get(out var data))
{
data.window_mode = windowMode.ToString();
data.seconds_opened = elapsed.Seconds;
EditorAnalytics.SendEventWithLimit(Data.k_EventName, data);
}
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9b3c4db4ffda4ec996c83a20adf76676
timeCreated: 1666684497

View File

@@ -0,0 +1,42 @@
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.Rendering;
using Scene = UnityEditor.SearchService.SceneSearch;
namespace UnityEditor.Rendering.Analytics
{
// schema = com.unity3d.data.schemas.editor.analytics.uVolumePriorityUsageAnalyticData_v2
// taxonomy = editor.analytics.uVolumePriorityUsageAnalyticData.v2
internal class VolumePriorityUsageAnalytic
{
[System.Diagnostics.DebuggerDisplay("{volume_name} - {scene_name} - {priority}")]
class Data
{
internal const string k_EventName = "uVolumePriorityUsageAnalyticData";
internal const int k_Version = 2;
// Naming convention for analytics data
public string volume_name;
public string scene_name;
public float priority;
}
public static void Send(Volume volume)
{
if (volume == null || !AnalyticsUtils.TryRegisterEvent(Data.k_EventName, Data.k_Version))
return;
var scene = EditorSceneManager.GetActiveScene();
if (!scene.IsValid())
return;
using (GenericPool<Data>.Get(out var data))
{
data.volume_name = Hash128.Compute(volume.name).ToString();
data.scene_name = AssetDatabase.AssetPathToGUID(scene.path);
data.priority = volume.priority;
AnalyticsUtils.SendData<Data>(data, Data.k_EventName, Data.k_Version);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b29e0569eca4bc54da7a07d64b33e1b2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,83 @@
using System.Collections.Generic;
using JetBrains.Annotations;
using System.Diagnostics.CodeAnalysis;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering.Analytics
{
// schema = com.unity3d.data.schemas.editor.analytics.uVolumeProfileOverridesAnalytic_v2
// taxonomy = editor.analytics.uVolumeProfileOverridesAnalytic.v2
internal class VolumeProfileOverridesAnalytic : IPostprocessBuildWithReport
{
public int callbackOrder => int.MaxValue;
[System.Diagnostics.DebuggerDisplay("{volume_profile_asset_guid} - {component_type} - {overrided_parameters.Length}")]
struct Data
{
internal const string k_EventName = "uVolumeProfileOverridesAnalytic";
internal const int k_Version = 2;
// Naming convention for analytics data
public string volume_profile_asset_guid;
public string component_type;
public string[] overrided_parameters;
}
void IPostprocessBuildWithReport.OnPostprocessBuild(BuildReport _)
{
SendAnalyitic();
}
private static readonly string[] k_SearchFolders = new[] { "Assets" };
[MustUseReturnValue]
static bool TryGatherData([NotNullWhen(true)] out List<Data> datas, [NotNullWhen(false)] out string warning)
{
warning = string.Empty;
datas = new List<Data>();
var volumeProfileGUIDs = AssetDatabase.FindAssets($"t:{nameof(VolumeProfile)} glob:\"**/*.asset\"", k_SearchFolders);
foreach (var guid in volumeProfileGUIDs)
{
var volumeProfile = AssetDatabase.LoadAssetAtPath<VolumeProfile>(AssetDatabase.GUIDToAssetPath(guid));
if (volumeProfile == null)
continue;
foreach (var volumeComponent in volumeProfile.components)
{
var volumeComponentType = volumeComponent.GetType();
var overrideParameters =
volumeComponent.ToNestedColumnWithDefault(VolumeManager.instance.GetDefaultVolumeComponent(volumeComponentType),
true);
if (overrideParameters.Length == 0)
continue;
datas.Add(new Data()
{
volume_profile_asset_guid = guid,
component_type = volumeComponent.GetType().Name,
overrided_parameters = overrideParameters
});
}
}
return true;
}
[MenuItem("internal:Edit/Rendering/Analytics/Send VolumeProfileOverridesAnalytic ", priority = 1)]
static void SendAnalyitic()
{
if(!AnalyticsUtils.TryRegisterEvent(Data.k_EventName, Data.k_Version, maxEventPerHour: 1000))
return;
if (!TryGatherData(out var data, out var warning))
Debug.Log(warning);
data.ForEach(d => AnalyticsUtils.SendData(d, Data.k_EventName, Data.k_Version));
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3e30261210b9c0040baf9d684f0b3e8d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,41 @@
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering.Analytics
{
// schema = com.unity3d.data.schemas.editor.analytics.uVolumeProfileUsageAnalytic_v4
// taxonomy = editor.analytics.uVolumeProfileUsageAnalytic.v4
internal class VolumeProfileUsageAnalytic
{
[System.Diagnostics.DebuggerDisplay("{volume_name} - {scene_name}- {volume_profile_asset_guid}")]
class Data
{
internal const string k_EventName = "uVolumeProfileUsageAnalytic";
internal const int k_Version = 4;
// Naming convention for analytics data
public string volume_name;
public string scene_name;
public string volume_profile_asset_guid;
}
public static void Send(Volume volume, VolumeProfile volumeProfile)
{
if (volume == null || volumeProfile == null || !AnalyticsUtils.TryRegisterEvent(Data.k_EventName, Data.k_Version))
return;
var scene = EditorSceneManager.GetActiveScene();
if (!scene.IsValid())
return;
using (GenericPool<Data>.Get(out var data))
{
data.volume_name = Hash128.Compute(volume.name).ToString();
data.scene_name = AssetDatabase.AssetPathToGUID(scene.path);
data.volume_profile_asset_guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(volumeProfile.GetInstanceID()));
AnalyticsUtils.SendData<Data>(data, Data.k_EventName, Data.k_Version);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e7e0182f8c41fea4aaebcffa2915a381
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: