A game about forced loneliness, made by TACStudios
1#if ENABLE_INPUT_SYSTEM && ENABLE_INPUT_SYSTEM_PACKAGE
2#define USE_INPUT_SYSTEM
3using UnityEngine.InputSystem;
4using UnityEngine.InputSystem.UI;
5using UnityEngine.InputSystem.EnhancedTouch;
6#endif
7using System;
8using System.Collections;
9using System.Diagnostics;
10using UnityEngine.EventSystems;
11
12namespace UnityEngine.Rendering
13{
14 [CoreRPHelpURL("Rendering-Debugger")]
15 class DebugUpdater : MonoBehaviour
16 {
17 static DebugUpdater s_Instance = null;
18
19 ScreenOrientation m_Orientation;
20 bool m_RuntimeUiWasVisibleLastFrame = false;
21
22 [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
23 static void RuntimeInit()
24 {
25#if DEVELOPMENT_BUILD || UNITY_EDITOR
26 if (DebugManager.instance.enableRuntimeUI)
27 EnableRuntime();
28#endif
29 }
30
31 internal static void SetEnabled(bool enabled)
32 {
33 if (enabled)
34 EnableRuntime();
35 else
36 DisableRuntime();
37 }
38
39 static void EnableRuntime()
40 {
41 if (s_Instance != null)
42 return;
43
44 var go = new GameObject { name = "[Debug Updater]" };
45 s_Instance = go.AddComponent<DebugUpdater>();
46 s_Instance.m_Orientation = Screen.orientation;
47
48 DontDestroyOnLoad(go);
49
50 DebugManager.instance.EnableInputActions();
51
52#if USE_INPUT_SYSTEM
53 EnhancedTouchSupport.Enable();
54#endif
55 }
56
57 static void DisableRuntime()
58 {
59 DebugManager debugManager = DebugManager.instance;
60 debugManager.displayRuntimeUI = false;
61 debugManager.displayPersistentRuntimeUI = false;
62
63 if (s_Instance != null)
64 {
65 CoreUtils.Destroy(s_Instance.gameObject);
66 s_Instance = null;
67 }
68 }
69
70 internal static void HandleInternalEventSystemComponents(bool uiEnabled)
71 {
72 if (s_Instance == null)
73 return;
74
75 if (uiEnabled)
76 s_Instance.EnsureExactlyOneEventSystem();
77 else
78 s_Instance.DestroyDebugEventSystem();
79 }
80
81 void EnsureExactlyOneEventSystem()
82 {
83 var eventSystems = FindObjectsByType<EventSystem>(FindObjectsSortMode.None);
84 var debugEventSystem = GetComponent<EventSystem>();
85
86 if (eventSystems.Length > 1 && debugEventSystem != null)
87 {
88 Debug.Log($"More than one EventSystem detected in scene. Destroying EventSystem owned by DebugUpdater.");
89 DestroyDebugEventSystem();
90 }
91 else if (eventSystems.Length == 0)
92 {
93 Debug.Log($"No EventSystem available. Creating a new EventSystem to enable Rendering Debugger runtime UI.");
94 CreateDebugEventSystem();
95 }
96 else
97 {
98 StartCoroutine(DoAfterInputModuleUpdated(CheckInputModuleExists));
99 }
100 }
101
102 IEnumerator DoAfterInputModuleUpdated(Action action)
103 {
104 // EventSystem.current.currentInputModule is not updated immediately when EventSystem.current changes. It happens
105 // with a delay in EventSystem.Update(), so wait a couple of frames to ensure that has happened.
106 yield return new WaitForEndOfFrame();
107 yield return new WaitForEndOfFrame();
108
109 action.Invoke();
110 }
111
112 void CheckInputModuleExists()
113 {
114 if (EventSystem.current != null && EventSystem.current.currentInputModule == null)
115 {
116 Debug.LogWarning("Found a game object with EventSystem component but no corresponding BaseInputModule component - Debug UI input might not work correctly.");
117 }
118 }
119
120#if USE_INPUT_SYSTEM
121 void AssignDefaultActions()
122 {
123 if (EventSystem.current != null && EventSystem.current.currentInputModule is InputSystemUIInputModule inputSystemModule)
124 {
125 // FIXME: In order to activate default input actions in player builds (required for touch input to work),
126 // we need to call InputSystemUIInputModule.AssignDefaultActions() which was added in com.unity.inputsystem@1.1.0-pre.5.
127 // However, there is a problem in InputSystem package version ordering, where it sorts this version as an
128 // older version than it should be. Hence we cannot write a version define to conditionally compile this function call.
129 // Instead, we use reflection to see if the function is there and can be invoked.
130 //
131 // Once com.unity.inputsystem@1.1.0 is available, create an INPUTSYSTEM_1_1_0_OR_GREATER version define and use it
132 // to conditionally call AssignDefaultActions().
133 System.Reflection.MethodInfo assignDefaultActionsMethod = inputSystemModule.GetType().GetMethod("AssignDefaultActions");
134 if (assignDefaultActionsMethod != null)
135 {
136 assignDefaultActionsMethod.Invoke(inputSystemModule, null);
137 }
138 }
139
140 CheckInputModuleExists();
141 }
142#endif
143
144 void CreateDebugEventSystem()
145 {
146 gameObject.AddComponent<EventSystem>();
147#if USE_INPUT_SYSTEM
148 gameObject.AddComponent<InputSystemUIInputModule>();
149 StartCoroutine(DoAfterInputModuleUpdated(AssignDefaultActions));
150#else
151 gameObject.AddComponent<StandaloneInputModule>();
152#endif
153 }
154
155 void DestroyDebugEventSystem()
156 {
157 var eventSystem = GetComponent<EventSystem>();
158#if USE_INPUT_SYSTEM
159 var inputModule = GetComponent<InputSystemUIInputModule>();
160 if (inputModule)
161 {
162 CoreUtils.Destroy(inputModule);
163 StartCoroutine(DoAfterInputModuleUpdated(AssignDefaultActions));
164 }
165#else
166 CoreUtils.Destroy(GetComponent<StandaloneInputModule>());
167 CoreUtils.Destroy(GetComponent<BaseInput>());
168#endif
169 CoreUtils.Destroy(eventSystem);
170 }
171
172 void Update()
173 {
174 DebugManager debugManager = DebugManager.instance;
175
176 // Runtime UI visibility can change i.e. due to scene unload - allow component cleanup in this case.
177 if (m_RuntimeUiWasVisibleLastFrame != debugManager.displayRuntimeUI)
178 {
179 HandleInternalEventSystemComponents(debugManager.displayRuntimeUI);
180 }
181
182 debugManager.UpdateActions();
183
184 if (debugManager.GetAction(DebugAction.EnableDebugMenu) != 0.0f ||
185 debugManager.GetActionToggleDebugMenuWithTouch())
186 {
187 debugManager.displayRuntimeUI = !debugManager.displayRuntimeUI;
188 }
189
190 if (debugManager.displayRuntimeUI)
191 {
192 if (debugManager.GetAction(DebugAction.ResetAll) != 0.0f)
193 debugManager.Reset();
194
195 if (debugManager.GetActionReleaseScrollTarget())
196 debugManager.SetScrollTarget(null); // Allow mouse wheel scroll without causing auto-scroll
197 }
198
199 if (m_Orientation != Screen.orientation)
200 {
201 StartCoroutine(RefreshRuntimeUINextFrame());
202 m_Orientation = Screen.orientation;
203 }
204
205 m_RuntimeUiWasVisibleLastFrame = debugManager.displayRuntimeUI;
206 }
207
208 static IEnumerator RefreshRuntimeUINextFrame()
209 {
210 yield return null; // Defer runtime UI refresh to next frame to allow canvas to update first.
211 DebugManager.instance.ReDrawOnScreenDebug();
212 }
213 }
214}