A game about forced loneliness, made by TACStudios
1#if UNITY_EDITOR
2using System;
3using System.Linq;
4using UnityEditor;
5using UnityEngine.InputSystem.Users;
6
7namespace UnityEngine.InputSystem.Editor
8{
9 /// <summary>
10 /// Custom inspector for <see cref="PlayerInputManager"/>.
11 /// </summary>
12 [CustomEditor(typeof(PlayerInputManager))]
13 internal class PlayerInputManagerEditor : UnityEditor.Editor
14 {
15 public void OnEnable()
16 {
17 InputUser.onChange += OnUserChange;
18 }
19
20 public void OnDisable()
21 {
22 new InputComponentEditorAnalytic(InputSystemComponent.PlayerInputManager).Send();
23 new PlayerInputManagerEditorAnalytic(this).Send();
24 }
25
26 public void OnDestroy()
27 {
28 InputUser.onChange -= OnUserChange;
29 }
30
31 private void OnUserChange(InputUser user, InputUserChange change, InputDevice device)
32 {
33 Repaint();
34 }
35
36 public override void OnInspectorGUI()
37 {
38 ////TODO: cache properties
39
40 EditorGUI.BeginChangeCheck();
41
42 DoNotificationSectionUI();
43 EditorGUILayout.Space();
44 DoJoinSectionUI();
45 EditorGUILayout.Space();
46 DoSplitScreenSectionUI();
47
48 if (EditorGUI.EndChangeCheck())
49 serializedObject.ApplyModifiedProperties();
50
51 if (EditorApplication.isPlaying)
52 DoDebugUI();
53 }
54
55 private void DoNotificationSectionUI()
56 {
57 var notificationBehaviorProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_NotificationBehavior));
58 EditorGUILayout.PropertyField(notificationBehaviorProperty);
59 switch ((PlayerNotifications)notificationBehaviorProperty.intValue)
60 {
61 case PlayerNotifications.SendMessages:
62 if (m_SendMessagesHelpText == null)
63 m_SendMessagesHelpText = EditorGUIUtility.TrTextContent(
64 $"Will SendMessage() to GameObject: " + string.Join(",", PlayerInputManager.messages));
65 EditorGUILayout.HelpBox(m_SendMessagesHelpText);
66 break;
67
68 case PlayerNotifications.BroadcastMessages:
69 if (m_BroadcastMessagesHelpText == null)
70 m_BroadcastMessagesHelpText = EditorGUIUtility.TrTextContent(
71 $"Will BroadcastMessage() to GameObject: " + string.Join(",", PlayerInputManager.messages));
72 EditorGUILayout.HelpBox(m_BroadcastMessagesHelpText);
73 break;
74
75 case PlayerNotifications.InvokeUnityEvents:
76 m_EventsExpanded = EditorGUILayout.Foldout(m_EventsExpanded, m_EventsLabel, toggleOnLabelClick: true);
77 if (m_EventsExpanded)
78 {
79 var playerJoinedEventProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_PlayerJoinedEvent));
80 var playerLeftEventProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_PlayerLeftEvent));
81
82 EditorGUILayout.PropertyField(playerJoinedEventProperty);
83 EditorGUILayout.PropertyField(playerLeftEventProperty);
84 }
85 break;
86 }
87 }
88
89 private void DoJoinSectionUI()
90 {
91 EditorGUILayout.LabelField(m_JoiningGroupLabel, EditorStyles.boldLabel);
92
93 // Join behavior
94 var joinBehaviorProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_JoinBehavior));
95 EditorGUILayout.PropertyField(joinBehaviorProperty);
96 if ((PlayerJoinBehavior)joinBehaviorProperty.intValue != PlayerJoinBehavior.JoinPlayersManually)
97 {
98 ++EditorGUI.indentLevel;
99
100 // Join action.
101 if ((PlayerJoinBehavior)joinBehaviorProperty.intValue ==
102 PlayerJoinBehavior.JoinPlayersWhenJoinActionIsTriggered)
103 {
104 var joinActionProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_JoinAction));
105 EditorGUILayout.PropertyField(joinActionProperty);
106 }
107
108 // Player prefab.
109 var playerPrefabProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_PlayerPrefab));
110 EditorGUILayout.PropertyField(playerPrefabProperty);
111
112 ValidatePlayerPrefab(joinBehaviorProperty, playerPrefabProperty);
113
114 --EditorGUI.indentLevel;
115 }
116
117 // Enabled-by-default.
118 var allowJoiningProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_AllowJoining));
119 if (m_AllowingJoiningLabel == null)
120 m_AllowingJoiningLabel = new GUIContent("Joining Enabled By Default", allowJoiningProperty.GetTooltip());
121 EditorGUILayout.PropertyField(allowJoiningProperty, m_AllowingJoiningLabel);
122
123 // Max player count.
124 var maxPlayerCountProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_MaxPlayerCount));
125 if (m_EnableMaxPlayerCountLabel == null)
126 m_EnableMaxPlayerCountLabel = EditorGUIUtility.TrTextContent("Limit Number of Players", maxPlayerCountProperty.GetTooltip());
127 if (maxPlayerCountProperty.intValue > 0)
128 m_MaxPlayerCountEnabled = true;
129 m_MaxPlayerCountEnabled = EditorGUILayout.Toggle(m_EnableMaxPlayerCountLabel, m_MaxPlayerCountEnabled);
130 if (m_MaxPlayerCountEnabled)
131 {
132 ++EditorGUI.indentLevel;
133 if (maxPlayerCountProperty.intValue < 0)
134 maxPlayerCountProperty.intValue = 1;
135 EditorGUILayout.PropertyField(maxPlayerCountProperty);
136 --EditorGUI.indentLevel;
137 }
138 else
139 maxPlayerCountProperty.intValue = -1;
140 }
141
142 private static void ValidatePlayerPrefab(SerializedProperty joinBehaviorProperty,
143 SerializedProperty playerPrefabProperty)
144 {
145 if ((PlayerJoinBehavior)joinBehaviorProperty.intValue != PlayerJoinBehavior.JoinPlayersWhenButtonIsPressed)
146 return;
147
148 if (playerPrefabProperty.objectReferenceValue == null)
149 return;
150
151 var playerInput = ((GameObject)playerPrefabProperty.objectReferenceValue)
152 .GetComponentInChildren<PlayerInput>();
153
154 if (playerInput == null)
155 {
156 EditorGUILayout.HelpBox("No PlayerInput component found in player prefab.", MessageType.Info);
157 return;
158 }
159
160 if (playerInput.actions == null)
161 {
162 EditorGUILayout.HelpBox("PlayerInput component has no input action asset assigned.", MessageType.Info);
163 return;
164 }
165
166 if (playerInput.actions.controlSchemes.Any(c => c.deviceRequirements.Count > 0) == false)
167 EditorGUILayout.HelpBox("Join Players When Button Is Pressed behavior will not work when the Input Action Asset " +
168 "assigned to the PlayerInput component has no required devices in any control scheme.",
169 MessageType.Info);
170 }
171
172 private void DoSplitScreenSectionUI()
173 {
174 EditorGUILayout.LabelField(m_SplitScreenGroupLabel, EditorStyles.boldLabel);
175
176 // Split-screen toggle.
177 var splitScreenProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_SplitScreen));
178 if (m_SplitScreenLabel == null)
179 m_SplitScreenLabel = new GUIContent("Enable Split-Screen", splitScreenProperty.GetTooltip());
180 EditorGUILayout.PropertyField(splitScreenProperty, m_SplitScreenLabel);
181 if (!splitScreenProperty.boolValue)
182 return;
183
184 ++EditorGUI.indentLevel;
185
186 // Maintain-aspect-ratio toggle.
187 var maintainAspectRatioProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_MaintainAspectRatioInSplitScreen));
188 if (m_MaintainAspectRatioLabel == null)
189 m_MaintainAspectRatioLabel =
190 new GUIContent("Maintain Aspect Ratio", maintainAspectRatioProperty.GetTooltip());
191 EditorGUILayout.PropertyField(maintainAspectRatioProperty, m_MaintainAspectRatioLabel);
192
193 // Fixed-number toggle.
194 var fixedNumberProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_FixedNumberOfSplitScreens));
195 if (m_EnableFixedNumberOfSplitScreensLabel == null)
196 m_EnableFixedNumberOfSplitScreensLabel = EditorGUIUtility.TrTextContent("Set Fixed Number", fixedNumberProperty.GetTooltip());
197 if (fixedNumberProperty.intValue > 0)
198 m_FixedNumberOfSplitScreensEnabled = true;
199 m_FixedNumberOfSplitScreensEnabled = EditorGUILayout.Toggle(m_EnableFixedNumberOfSplitScreensLabel,
200 m_FixedNumberOfSplitScreensEnabled);
201 if (m_FixedNumberOfSplitScreensEnabled)
202 {
203 ++EditorGUI.indentLevel;
204 if (fixedNumberProperty.intValue < 0)
205 fixedNumberProperty.intValue = 4;
206 if (m_FixedNumberOfSplitScreensLabel == null)
207 m_FixedNumberOfSplitScreensLabel = EditorGUIUtility.TrTextContent("Number of Screens",
208 fixedNumberProperty.tooltip);
209 EditorGUILayout.PropertyField(fixedNumberProperty, m_FixedNumberOfSplitScreensLabel);
210 --EditorGUI.indentLevel;
211 }
212 else
213 {
214 fixedNumberProperty.intValue = -1;
215 }
216
217 // Split-screen area.
218 var splitScreenAreaProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_SplitScreenRect));
219 if (m_SplitScreenAreaLabel == null)
220 m_SplitScreenAreaLabel = new GUIContent("Screen Rectangle", splitScreenAreaProperty.GetTooltip());
221 EditorGUILayout.PropertyField(splitScreenAreaProperty, m_SplitScreenAreaLabel);
222
223 --EditorGUI.indentLevel;
224 }
225
226 private void DoDebugUI()
227 {
228 EditorGUILayout.Space();
229 EditorGUILayout.LabelField(m_DebugLabel, EditorStyles.boldLabel);
230 EditorGUI.BeginDisabledGroup(true);
231
232 var players = PlayerInput.all;
233 if (players.Count == 0)
234 {
235 EditorGUILayout.LabelField("No Players");
236 }
237 else
238 {
239 foreach (var player in players)
240 {
241 var str = player.gameObject.name;
242 if (player.splitScreenIndex != -1)
243 str += $" (Screen #{player.splitScreenIndex})";
244 EditorGUILayout.LabelField("Player #" + player.playerIndex, str);
245 }
246 }
247 EditorGUI.EndDisabledGroup();
248 }
249
250 [SerializeField] private bool m_EventsExpanded;
251 [SerializeField] private bool m_MaxPlayerCountEnabled;
252 [SerializeField] private bool m_FixedNumberOfSplitScreensEnabled;
253
254 [NonSerialized] private readonly GUIContent m_JoiningGroupLabel = EditorGUIUtility.TrTextContent("Joining");
255 [NonSerialized] private readonly GUIContent m_SplitScreenGroupLabel = EditorGUIUtility.TrTextContent("Split-Screen");
256 [NonSerialized] private readonly GUIContent m_EventsLabel = EditorGUIUtility.TrTextContent("Events");
257 [NonSerialized] private readonly GUIContent m_DebugLabel = EditorGUIUtility.TrTextContent("Debug");
258 [NonSerialized] private GUIContent m_SendMessagesHelpText;
259 [NonSerialized] private GUIContent m_BroadcastMessagesHelpText;
260 [NonSerialized] private GUIContent m_AllowingJoiningLabel;
261 [NonSerialized] private GUIContent m_SplitScreenLabel;
262 [NonSerialized] private GUIContent m_MaintainAspectRatioLabel;
263 [NonSerialized] private GUIContent m_SplitScreenAreaLabel;
264 [NonSerialized] private GUIContent m_FixedNumberOfSplitScreensLabel;
265 [NonSerialized] private GUIContent m_EnableMaxPlayerCountLabel;
266 [NonSerialized] private GUIContent m_EnableFixedNumberOfSplitScreensLabel;
267 }
268}
269#endif // UNITY_EDITOR