#if UNITY_EDITOR using System; using UnityEditor; using UnityEngine.Serialization; namespace UnityEngine.InputSystem.Editor { #if UNITY_2023_2_OR_NEWER [UnityEngine.Analytics.AnalyticInfo(eventName: kEventName, maxEventsPerHour: kMaxEventsPerHour, maxNumberOfElements: kMaxNumberOfElements, vendorKey: UnityEngine.InputSystem.InputAnalytics.kVendorKey)] #endif // UNITY_2023_2_OR_NEWER internal class InputExitPlayModeAnalytic : UnityEngine.InputSystem.InputAnalytics.IInputAnalytic { public const string kEventName = "input_exit_playmode"; public const int kMaxEventsPerHour = 100; // default: 1000 public const int kMaxNumberOfElements = 100; // default: 1000 /// /// Enumeration type for code authoring APIs mapping to . /// /// /// This enumeration type may be added to, but NEVER changed, since it would break older data. /// public enum Api { AddBinding = 0, AddCompositeBinding = 1, ChangeBinding = 2, ChangeCompositeBinding = 3, Rename = 4, AddControlScheme = 5, RemoveControlScheme = 6, ControlSchemeWithBindingGroup = 7, ControlSchemeWithDevice = 8, ControlSchemeWithRequiredDevice = 9, ControlSchemeWithOptionalDevice = 10, ControlSchemeOrWithRequiredDevice = 11, ControlSchemeOrWithOptionalDevice = 12 } private static readonly int[] m_Counters = new int[Enum.GetNames(typeof(Api)).Length]; /// /// Registers a call to the associated API. /// /// Enumeration identifying the API. public static void Register(Api api) { if (suppress) return; // Note: Currently discards detailed information and only sets a boolean (aggregated) value. ++m_Counters[(int)api]; } /// /// Suppresses the registration of analytics. /// /// /// May be used to temporarily suppress analytics to avoid false positives from internal usage. /// public static bool suppress { get; set; } // Cache delegate private static readonly Action PlayModeChanged = OnPlayModeStateChange; // Note: Internal visibility to simplify unit testing internal static void OnPlayModeStateChange(PlayModeStateChange change) { if (change == PlayModeStateChange.ExitingEditMode) { // Reset all counters when exiting edit mode Array.Clear(m_Counters, 0, m_Counters.Length); // Make sure not suppressed suppress = false; } if (change == PlayModeStateChange.ExitingPlayMode) { // Send analytics and unhook delegate when exiting play-mode EditorApplication.playModeStateChanged -= PlayModeChanged; new InputExitPlayModeAnalytic().Send(); // No reason to not suppress suppress = true; } } [InitializeOnEnterPlayMode] private static void Hook() { // Make sure only a single play-mode change delegate is registered EditorApplication.playModeStateChanged -= PlayModeChanged; EditorApplication.playModeStateChanged += PlayModeChanged; } private InputExitPlayModeAnalytic() { info = new InputAnalytics.InputAnalyticInfo(kEventName, kMaxEventsPerHour, kMaxNumberOfElements); } /// /// Represents data collected when exiting play-mode.. /// /// /// Ideally this struct should be readonly but then Unity cannot serialize/deserialize it. /// [Serializable] public struct Data : UnityEngine.InputSystem.InputAnalytics.IInputAnalyticData { /// /// Creates a new Data instance. /// /// Specifies whether code authoring has been used during play-mode. public Data(bool usesCodeAuthoring) { uses_code_authoring = usesCodeAuthoring; } /// /// Specifies whether code-authoring (Input Action setup via extensions) was used at least once during play-mode. /// public bool uses_code_authoring; } #if UNITY_2023_2_OR_NEWER public bool TryGatherData(out UnityEngine.Analytics.IAnalytic.IData data, out Exception error) #else public bool TryGatherData(out InputAnalytics.IInputAnalyticData data, out Exception error) #endif { try { // Determine aggregated perspective, i.e. was "any" code-authoring API used var usedCodeAuthoringDuringPlayMode = false; for (var i = 0; i < m_Counters.Length; ++i) { if (m_Counters[i] > 0) { usedCodeAuthoringDuringPlayMode = true; break; } } data = new Data(usedCodeAuthoringDuringPlayMode); error = null; return true; } catch (Exception e) { data = null; error = e; return false; } } public InputAnalytics.InputAnalyticInfo info { get; } } } #endif // UNITY_EDITOR