No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PlayerInputManagerEditor.cs 12KB

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