using System; using UnityEngine.InputSystem.Layouts; ////TODO: ManualThreaded namespace UnityEngine.InputSystem.LowLevel { /// /// Enum of different player loop positions where the input system can invoke its update mechanism. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1714:FlagsEnumsShouldHavePluralNames", Justification = "Not consistently used as flags, many using APIs expect only one type to be passed.")] [Flags] public enum InputUpdateType { /// /// Performs no actual update but still allows devices to reset themselves. Usually occurs immediately after domain reload. /// None = 0, /// /// Update corresponding to Update. /// /// Every frame has exactly one dynamic update. If not reconfigured using , /// the dynamic update happens after all the fixed updates for the frame have run (which can be /// zero or more). /// /// Input updates run before script callbacks on MonoBehaviours are fired. /// Dynamic = 1 << 0, /// /// Update corresponding to FixedUpdate. /// /// Every frame has zero or more fixed updates. These are run before the dynamic update for the /// frame. /// /// Input updates run before script callbacks on MonoBehaviours are fired. /// Fixed = 1 << 1, ////REVIEW: Axe this update type from the public API? /// /// Input update that happens right before rendering. /// /// The BeforeRender update affects only devices that have before-render updates enabled. This /// has to be done through a device's layout ( /// and is visible through . /// /// BeforeRender updates are useful to minimize lag of transform data that is used in rendering /// but is coming from external tracking devices. An example are HMDs. If the head transform used /// for the render camera is not synchronized right before rendering, it can result in a noticeable /// lag between head and camera movement. /// BeforeRender = 1 << 2, /// /// Input update that happens right before s are updated. /// /// This update only occurs in the editor. It is triggered right before . /// Editor = 1 << 3, /// /// Input updates do not happen automatically but have to be triggered manually by calling . /// Manual = 1 << 4, /// /// Default update mask. Combines , , and . /// Default = Dynamic | Fixed | Editor, } internal static class InputUpdate { public static uint s_UpdateStepCount; // read only, but kept as a variable for performance reasons public static InputUpdateType s_LatestUpdateType; public static UpdateStepCount s_PlayerUpdateStepCount; #if UNITY_EDITOR public static InputUpdateType s_LatestNonEditorUpdateType; public static UpdateStepCount s_EditorUpdateStepCount; #endif [Serializable] public struct UpdateStepCount { private bool m_WasUpdated; public uint value { get; private set; } public void OnBeforeUpdate() { m_WasUpdated = true; value++; } public void OnUpdate() { // only increment if OnBeforeUpdate was not called if (!m_WasUpdated) value++; m_WasUpdated = false; } }; [Serializable] public struct SerializedState { public InputUpdateType lastUpdateType; public UpdateStepCount playerUpdateStepCount; #if UNITY_EDITOR public InputUpdateType lastNonEditorUpdateType; public UpdateStepCount editorUpdateStepCount; #endif } internal static void OnBeforeUpdate(InputUpdateType type) { s_LatestUpdateType = type; switch (type) { case InputUpdateType.Dynamic: case InputUpdateType.Manual: case InputUpdateType.Fixed: s_PlayerUpdateStepCount.OnBeforeUpdate(); s_UpdateStepCount = s_PlayerUpdateStepCount.value; #if UNITY_EDITOR s_LatestNonEditorUpdateType = type; #endif break; #if UNITY_EDITOR case InputUpdateType.Editor: s_EditorUpdateStepCount.OnBeforeUpdate(); s_UpdateStepCount = s_EditorUpdateStepCount.value; break; #endif } } internal static void OnUpdate(InputUpdateType type) { s_LatestUpdateType = type; switch (type) { case InputUpdateType.Dynamic: case InputUpdateType.Manual: case InputUpdateType.Fixed: s_PlayerUpdateStepCount.OnUpdate(); s_UpdateStepCount = s_PlayerUpdateStepCount.value; #if UNITY_EDITOR s_LatestNonEditorUpdateType = type; #endif break; #if UNITY_EDITOR case InputUpdateType.Editor: s_EditorUpdateStepCount.OnUpdate(); s_UpdateStepCount = s_EditorUpdateStepCount.value; break; #endif } } #if UNITY_EDITOR internal static void RestoreStateAfterEditorUpdate() { s_LatestUpdateType = s_LatestNonEditorUpdateType; s_UpdateStepCount = s_PlayerUpdateStepCount.value; } #endif public static SerializedState Save() { return new SerializedState { lastUpdateType = s_LatestUpdateType, playerUpdateStepCount = s_PlayerUpdateStepCount, #if UNITY_EDITOR lastNonEditorUpdateType = s_LatestNonEditorUpdateType, editorUpdateStepCount = s_EditorUpdateStepCount #endif }; } public static void Restore(SerializedState state) { s_LatestUpdateType = state.lastUpdateType; s_PlayerUpdateStepCount = state.playerUpdateStepCount; #if UNITY_EDITOR s_LatestNonEditorUpdateType = state.lastNonEditorUpdateType; s_EditorUpdateStepCount = state.editorUpdateStepCount; #endif switch (s_LatestUpdateType) { case InputUpdateType.Dynamic: case InputUpdateType.Manual: case InputUpdateType.Fixed: s_UpdateStepCount = s_PlayerUpdateStepCount.value; break; #if UNITY_EDITOR case InputUpdateType.Editor: s_UpdateStepCount = s_EditorUpdateStepCount.value; break; #endif default: // if there was no previous update type, reset the counter s_UpdateStepCount = 0; break; } } public static InputUpdateType GetUpdateTypeForPlayer(this InputUpdateType mask) { if ((mask & InputUpdateType.Manual) != 0) return InputUpdateType.Manual; if ((mask & InputUpdateType.Dynamic) != 0) return InputUpdateType.Dynamic; if ((mask & InputUpdateType.Fixed) != 0) return InputUpdateType.Fixed; return InputUpdateType.None; } public static bool IsPlayerUpdate(this InputUpdateType updateType) { if (updateType == InputUpdateType.Editor) return false; return updateType != default; } #if UNITY_EDITOR public static bool IsEditorUpdate(this InputUpdateType updateType) { return updateType == InputUpdateType.Editor; } #endif } }