This commit is contained in:
2025-01-17 13:10:42 +01:00
commit 4536213c91
15115 changed files with 1442174 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cc69a9a42102dea4dafad4147e3ed98e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
fileFormatVersion: 2
guid: ca9f5fa95ffab41fb9a615ab714db018
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 11500000, guid: 8404be70184654265930450def6a9037, type: 3}
generateWrapperCode: 0
wrapperCodePath:
wrapperClassName:
wrapperCodeNamespace: UnityEngine.InputSystem

View File

@@ -0,0 +1,52 @@
using System;
using System.Diagnostics;
using UnityEngine.InputSystem.Controls;
////TODO: API to get the control and device from the internal context
////TODO: ToString()
namespace UnityEngine.InputSystem
{
/// <summary>
/// Wraps around values provided by input actions.
/// </summary>
/// <remarks>
/// This is a wrapper around <see cref="InputAction.CallbackContext"/> chiefly for use
/// with GameObject messages (i.e. <see cref="GameObject.SendMessage(string,object)"/>). It exists
/// so that action callback data can be represented as an object, can be reused, and shields
/// the receiver from having to know about action callback specifics.
/// </remarks>
/// <seealso cref="InputAction"/>
[DebuggerDisplay("Value = {Get()}")]
public class InputValue
{
/// <summary>
/// Read the value as an object.
/// </summary>
/// <remarks>
/// This method allocates GC memory and will thus created garbage. If used during gameplay,
/// it will lead to GC spikes.
/// </remarks>
/// <returns>The current value in the form of a boxed object.</returns>
public object Get()
{
return m_Context.Value.ReadValueAsObject();
}
////TODO: add automatic conversions
public TValue Get<TValue>()
where TValue : struct
{
if (!m_Context.HasValue)
throw new InvalidOperationException($"Values can only be retrieved while in message callbacks");
return m_Context.Value.ReadValue<TValue>();
}
////TODO: proper message if value type isn't right
public bool isPressed => Get<float>() >= ButtonControl.s_GlobalDefaultButtonPressPoint;
internal InputAction.CallbackContext? m_Context;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b24da9e286b594ace8ec4dfd4a374780
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 62899f850307741f2a39c98a8b639597
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: -100
icon: {fileID: 2800000, guid: 40265a896a0f341bb956e90c59025a29, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 78dcfd26eada049b0840e276bd029712
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 621567455fd1c4ceb811cc8a00b6a1a5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 40265a896a0f341bb956e90c59025a29, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,269 @@
#if UNITY_EDITOR
using System;
using System.Linq;
using UnityEditor;
using UnityEngine.InputSystem.Users;
namespace UnityEngine.InputSystem.Editor
{
/// <summary>
/// Custom inspector for <see cref="PlayerInputManager"/>.
/// </summary>
[CustomEditor(typeof(PlayerInputManager))]
internal class PlayerInputManagerEditor : UnityEditor.Editor
{
public void OnEnable()
{
InputUser.onChange += OnUserChange;
}
public void OnDisable()
{
new InputComponentEditorAnalytic(InputSystemComponent.PlayerInputManager).Send();
new PlayerInputManagerEditorAnalytic(this).Send();
}
public void OnDestroy()
{
InputUser.onChange -= OnUserChange;
}
private void OnUserChange(InputUser user, InputUserChange change, InputDevice device)
{
Repaint();
}
public override void OnInspectorGUI()
{
////TODO: cache properties
EditorGUI.BeginChangeCheck();
DoNotificationSectionUI();
EditorGUILayout.Space();
DoJoinSectionUI();
EditorGUILayout.Space();
DoSplitScreenSectionUI();
if (EditorGUI.EndChangeCheck())
serializedObject.ApplyModifiedProperties();
if (EditorApplication.isPlaying)
DoDebugUI();
}
private void DoNotificationSectionUI()
{
var notificationBehaviorProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_NotificationBehavior));
EditorGUILayout.PropertyField(notificationBehaviorProperty);
switch ((PlayerNotifications)notificationBehaviorProperty.intValue)
{
case PlayerNotifications.SendMessages:
if (m_SendMessagesHelpText == null)
m_SendMessagesHelpText = EditorGUIUtility.TrTextContent(
$"Will SendMessage() to GameObject: " + string.Join(",", PlayerInputManager.messages));
EditorGUILayout.HelpBox(m_SendMessagesHelpText);
break;
case PlayerNotifications.BroadcastMessages:
if (m_BroadcastMessagesHelpText == null)
m_BroadcastMessagesHelpText = EditorGUIUtility.TrTextContent(
$"Will BroadcastMessage() to GameObject: " + string.Join(",", PlayerInputManager.messages));
EditorGUILayout.HelpBox(m_BroadcastMessagesHelpText);
break;
case PlayerNotifications.InvokeUnityEvents:
m_EventsExpanded = EditorGUILayout.Foldout(m_EventsExpanded, m_EventsLabel, toggleOnLabelClick: true);
if (m_EventsExpanded)
{
var playerJoinedEventProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_PlayerJoinedEvent));
var playerLeftEventProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_PlayerLeftEvent));
EditorGUILayout.PropertyField(playerJoinedEventProperty);
EditorGUILayout.PropertyField(playerLeftEventProperty);
}
break;
}
}
private void DoJoinSectionUI()
{
EditorGUILayout.LabelField(m_JoiningGroupLabel, EditorStyles.boldLabel);
// Join behavior
var joinBehaviorProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_JoinBehavior));
EditorGUILayout.PropertyField(joinBehaviorProperty);
if ((PlayerJoinBehavior)joinBehaviorProperty.intValue != PlayerJoinBehavior.JoinPlayersManually)
{
++EditorGUI.indentLevel;
// Join action.
if ((PlayerJoinBehavior)joinBehaviorProperty.intValue ==
PlayerJoinBehavior.JoinPlayersWhenJoinActionIsTriggered)
{
var joinActionProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_JoinAction));
EditorGUILayout.PropertyField(joinActionProperty);
}
// Player prefab.
var playerPrefabProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_PlayerPrefab));
EditorGUILayout.PropertyField(playerPrefabProperty);
ValidatePlayerPrefab(joinBehaviorProperty, playerPrefabProperty);
--EditorGUI.indentLevel;
}
// Enabled-by-default.
var allowJoiningProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_AllowJoining));
if (m_AllowingJoiningLabel == null)
m_AllowingJoiningLabel = new GUIContent("Joining Enabled By Default", allowJoiningProperty.GetTooltip());
EditorGUILayout.PropertyField(allowJoiningProperty, m_AllowingJoiningLabel);
// Max player count.
var maxPlayerCountProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_MaxPlayerCount));
if (m_EnableMaxPlayerCountLabel == null)
m_EnableMaxPlayerCountLabel = EditorGUIUtility.TrTextContent("Limit Number of Players", maxPlayerCountProperty.GetTooltip());
if (maxPlayerCountProperty.intValue > 0)
m_MaxPlayerCountEnabled = true;
m_MaxPlayerCountEnabled = EditorGUILayout.Toggle(m_EnableMaxPlayerCountLabel, m_MaxPlayerCountEnabled);
if (m_MaxPlayerCountEnabled)
{
++EditorGUI.indentLevel;
if (maxPlayerCountProperty.intValue < 0)
maxPlayerCountProperty.intValue = 1;
EditorGUILayout.PropertyField(maxPlayerCountProperty);
--EditorGUI.indentLevel;
}
else
maxPlayerCountProperty.intValue = -1;
}
private static void ValidatePlayerPrefab(SerializedProperty joinBehaviorProperty,
SerializedProperty playerPrefabProperty)
{
if ((PlayerJoinBehavior)joinBehaviorProperty.intValue != PlayerJoinBehavior.JoinPlayersWhenButtonIsPressed)
return;
if (playerPrefabProperty.objectReferenceValue == null)
return;
var playerInput = ((GameObject)playerPrefabProperty.objectReferenceValue)
.GetComponentInChildren<PlayerInput>();
if (playerInput == null)
{
EditorGUILayout.HelpBox("No PlayerInput component found in player prefab.", MessageType.Info);
return;
}
if (playerInput.actions == null)
{
EditorGUILayout.HelpBox("PlayerInput component has no input action asset assigned.", MessageType.Info);
return;
}
if (playerInput.actions.controlSchemes.Any(c => c.deviceRequirements.Count > 0) == false)
EditorGUILayout.HelpBox("Join Players When Button Is Pressed behavior will not work when the Input Action Asset " +
"assigned to the PlayerInput component has no required devices in any control scheme.",
MessageType.Info);
}
private void DoSplitScreenSectionUI()
{
EditorGUILayout.LabelField(m_SplitScreenGroupLabel, EditorStyles.boldLabel);
// Split-screen toggle.
var splitScreenProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_SplitScreen));
if (m_SplitScreenLabel == null)
m_SplitScreenLabel = new GUIContent("Enable Split-Screen", splitScreenProperty.GetTooltip());
EditorGUILayout.PropertyField(splitScreenProperty, m_SplitScreenLabel);
if (!splitScreenProperty.boolValue)
return;
++EditorGUI.indentLevel;
// Maintain-aspect-ratio toggle.
var maintainAspectRatioProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_MaintainAspectRatioInSplitScreen));
if (m_MaintainAspectRatioLabel == null)
m_MaintainAspectRatioLabel =
new GUIContent("Maintain Aspect Ratio", maintainAspectRatioProperty.GetTooltip());
EditorGUILayout.PropertyField(maintainAspectRatioProperty, m_MaintainAspectRatioLabel);
// Fixed-number toggle.
var fixedNumberProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_FixedNumberOfSplitScreens));
if (m_EnableFixedNumberOfSplitScreensLabel == null)
m_EnableFixedNumberOfSplitScreensLabel = EditorGUIUtility.TrTextContent("Set Fixed Number", fixedNumberProperty.GetTooltip());
if (fixedNumberProperty.intValue > 0)
m_FixedNumberOfSplitScreensEnabled = true;
m_FixedNumberOfSplitScreensEnabled = EditorGUILayout.Toggle(m_EnableFixedNumberOfSplitScreensLabel,
m_FixedNumberOfSplitScreensEnabled);
if (m_FixedNumberOfSplitScreensEnabled)
{
++EditorGUI.indentLevel;
if (fixedNumberProperty.intValue < 0)
fixedNumberProperty.intValue = 4;
if (m_FixedNumberOfSplitScreensLabel == null)
m_FixedNumberOfSplitScreensLabel = EditorGUIUtility.TrTextContent("Number of Screens",
fixedNumberProperty.tooltip);
EditorGUILayout.PropertyField(fixedNumberProperty, m_FixedNumberOfSplitScreensLabel);
--EditorGUI.indentLevel;
}
else
{
fixedNumberProperty.intValue = -1;
}
// Split-screen area.
var splitScreenAreaProperty = serializedObject.FindProperty(nameof(PlayerInputManager.m_SplitScreenRect));
if (m_SplitScreenAreaLabel == null)
m_SplitScreenAreaLabel = new GUIContent("Screen Rectangle", splitScreenAreaProperty.GetTooltip());
EditorGUILayout.PropertyField(splitScreenAreaProperty, m_SplitScreenAreaLabel);
--EditorGUI.indentLevel;
}
private void DoDebugUI()
{
EditorGUILayout.Space();
EditorGUILayout.LabelField(m_DebugLabel, EditorStyles.boldLabel);
EditorGUI.BeginDisabledGroup(true);
var players = PlayerInput.all;
if (players.Count == 0)
{
EditorGUILayout.LabelField("No Players");
}
else
{
foreach (var player in players)
{
var str = player.gameObject.name;
if (player.splitScreenIndex != -1)
str += $" (Screen #{player.splitScreenIndex})";
EditorGUILayout.LabelField("Player #" + player.playerIndex, str);
}
}
EditorGUI.EndDisabledGroup();
}
[SerializeField] private bool m_EventsExpanded;
[SerializeField] private bool m_MaxPlayerCountEnabled;
[SerializeField] private bool m_FixedNumberOfSplitScreensEnabled;
[NonSerialized] private readonly GUIContent m_JoiningGroupLabel = EditorGUIUtility.TrTextContent("Joining");
[NonSerialized] private readonly GUIContent m_SplitScreenGroupLabel = EditorGUIUtility.TrTextContent("Split-Screen");
[NonSerialized] private readonly GUIContent m_EventsLabel = EditorGUIUtility.TrTextContent("Events");
[NonSerialized] private readonly GUIContent m_DebugLabel = EditorGUIUtility.TrTextContent("Debug");
[NonSerialized] private GUIContent m_SendMessagesHelpText;
[NonSerialized] private GUIContent m_BroadcastMessagesHelpText;
[NonSerialized] private GUIContent m_AllowingJoiningLabel;
[NonSerialized] private GUIContent m_SplitScreenLabel;
[NonSerialized] private GUIContent m_MaintainAspectRatioLabel;
[NonSerialized] private GUIContent m_SplitScreenAreaLabel;
[NonSerialized] private GUIContent m_FixedNumberOfSplitScreensLabel;
[NonSerialized] private GUIContent m_EnableMaxPlayerCountLabel;
[NonSerialized] private GUIContent m_EnableFixedNumberOfSplitScreensLabel;
}
}
#endif // UNITY_EDITOR

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6247927155f224aa5a61c15611fcd34a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,34 @@
namespace UnityEngine.InputSystem
{
/// <summary>
/// Determines how <see cref="PlayerInputManager"/> joins new players.
/// </summary>
/// <remarks>
/// </remarks>
/// <seealso cref="PlayerInputManager"/>
/// <seealso cref="PlayerInputManager.joinBehavior"/>
public enum PlayerJoinBehavior
{
/// <summary>
/// Listen for button presses on devices that are not paired to any player. If they occur
/// and joining is allowed, join a new player using the device the button was pressed on.
/// </summary>
JoinPlayersWhenButtonIsPressed,
JoinPlayersWhenJoinActionIsTriggered,
/// <summary>
/// Do not join players automatically. Call <see cref="PlayerInputManager.JoinPlayerFromUI"/> or <see cref="PlayerInputManager.JoinPlayerFromAction"/>
/// explicitly in order to join new players. Alternatively, just create GameObjects with <see cref="PlayerInput"/>
/// components directly and they will be joined automatically.
/// </summary>
/// <remarks>
/// This behavior also allows implementing more sophisticated device pairing mechanisms when multiple devices
/// are involved. While initial engagement required by <see cref="JoinPlayersWhenButtonIsPressed"/> or
/// <see cref="JoinPlayersWhenJoinActionIsTriggered"/> allows pairing a single device reliably to a player,
/// additional devices that may be required by a control scheme will still get paired automatically out of the
/// pool of available devices.
/// </remarks>
JoinPlayersManually,
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 86b230bdbb8ce487882861a17e6d2bde
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,44 @@
namespace UnityEngine.InputSystem
{
/// <summary>
/// Determines how the triggering of an action or other input-related events are relayed to other GameObjects.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1717:Only FlagsAttribute enums should have plural names")]
public enum PlayerNotifications
{
////TODO: add a "None" behavior; for actions, users may want to poll (or use the generated interfaces)
/// <summary>
/// Use <see cref="GameObject.SendMessage(string,object)"/> to send a message to the <see cref="GameObject"/>
/// that <see cref="PlayerInput"/> belongs to.
///
/// The message name will be the name of the action (e.g. "Jump"; it will not include the action map name),
/// and the object will be the <see cref="PlayerInput"/> on which the action was triggered.
///
/// If the notification is for an action that was triggered, <see cref="SendMessageOptions"/> will be
/// <see cref="SendMessageOptions.RequireReceiver"/> (i.e. an error will be logged if there is no corresponding
/// method). Otherwise it will be <see cref="SendMessageOptions.DontRequireReceiver"/>.
/// </summary>
SendMessages,
/// <summary>
/// Like <see cref="SendMessages"/> but instead of using <see cref="GameObject.SendMessage(string,object)"/>,
/// use <see cref="GameObject.BroadcastMessage(string,object)"/>.
/// </summary>
BroadcastMessages,
/// <summary>
/// Have a separate <a href="https://docs.unity3d.com/ScriptReference/Events.UnityEvent.html">UnityEvent</a> for each notification.
/// Allows wiring up target methods to invoke such that the connection is persisted in Unity serialized data.
///
/// See <see cref="PlayerInput.actionEvents"/> and related callbacks such as <see cref="PlayerInput.controlsChangedEvent"/>.
/// </summary>
InvokeUnityEvents,
////TODO: Kill
/// <summary>
/// Use plain C# callbacks.
/// </summary>
InvokeCSharpEvents
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 326532c3044e949b696215102693a1a3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: