diff --git a/Assets/Tests/InputSystem/Plugins/PlayerInputTests.cs b/Assets/Tests/InputSystem/Plugins/PlayerInputTests.cs index ece203817b..7bf1d5ee81 100644 --- a/Assets/Tests/InputSystem/Plugins/PlayerInputTests.cs +++ b/Assets/Tests/InputSystem/Plugins/PlayerInputTests.cs @@ -2405,6 +2405,39 @@ public void PlayerInput_CanDisableAfterAssigningAction_WithControlSchemesAndInte player.SetActive(false); // Should cause full rebinding and not assert } + [Test] + [Category("PlayerInput")] + public void PlayerInput_DelegatesAreUpdate_WhenActionMapAddedAfterAssignment() + { + var gamepad = InputSystem.AddDevice(); + + var go = new GameObject(); + var listener = go.AddComponent(); + var playerInput = go.AddComponent(); + playerInput.defaultActionMap = "Other"; + var actionAsset = InputActionAsset.FromJson(kActions); + playerInput.actions = actionAsset; + + // Disable the asset while adding another action map to it as none + // of the actions in the asset can be enabled during modification + // + actionAsset.Disable(); + var keyboard = InputSystem.AddDevice(); + var newActionMap = actionAsset.AddActionMap("NewMap"); + var newAction = newActionMap.AddAction("NewAction"); + newAction.AddBinding("/k", groups: "Keyboard"); + actionAsset.AddControlScheme("Keyboard").WithRequiredDevice(); + actionAsset.Enable(); + + playerInput.currentActionMap = newActionMap; + playerInput.ActivateInput(); + listener.messages.Clear(); + + Press(keyboard.kKey); + + Assert.That(listener.messages, Has.Exactly(1).With.Property("name").EqualTo("OnNewAction")); + } + private struct Message : IEquatable { public string name { get; set; } @@ -2477,6 +2510,11 @@ public void OnOtherAction(InputValue value) messages?.Add(new Message { name = "OnOtherAction", value = value.Get() }); } + public void OnNewAction(InputValue value) + { + messages?.Add(new Message { name = "OnNewAction", value = value.Get() }); + } + // ReSharper disable once UnusedMember.Local public void OnActionWithSpaces(InputValue value) { diff --git a/Packages/com.unity.inputsystem/CHANGELOG.md b/Packages/com.unity.inputsystem/CHANGELOG.md index cc01a91c60..21c891a88c 100644 --- a/Packages/com.unity.inputsystem/CHANGELOG.md +++ b/Packages/com.unity.inputsystem/CHANGELOG.md @@ -32,6 +32,7 @@ however, it has to be formatted properly to pass verification tests. - Fixed an issue in `Samples/Visualizers/GamepadVisualizer.unity` sample where the visualization wouldn't handle device disconnects or current device changes properly (ISXB-1243). - Fixed an issue when displaying Serialized InputAction's Processor properties inside the Inspector window. [ISXB-1269](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1269) - Fixed an issue with default device selection when adding new Control Scheme. +- Fixed an issue where action map delegates were not updated when the asset already assigned to the PlayerInput component were changed [ISXB-711](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-711). ### Changed - Added back the InputManager to InputSystem project-wide asset migration code with performance improvement (ISX-2086). diff --git a/Packages/com.unity.inputsystem/InputSystem/Plugins/PlayerInput/PlayerInput.cs b/Packages/com.unity.inputsystem/InputSystem/Plugins/PlayerInput/PlayerInput.cs index 66929b7c2b..1375503db1 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Plugins/PlayerInput/PlayerInput.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Plugins/PlayerInput/PlayerInput.cs @@ -950,6 +950,8 @@ public TDevice GetDevice() /// public void ActivateInput() { + UpdateDelegates(); + m_InputActive = true; // If we have no current action map but there's a default @@ -960,6 +962,31 @@ public void ActivateInput() m_CurrentActionMap?.Enable(); } + // Users can add and remove actions maps *after* assigning an InputActionAsset to the PlayerInput component. + // This ensures "actionTriggered" delegates are assigned for new maps (case isxb-711) + // + private int m_AllMapsHashCode = 0; + private void UpdateDelegates() + { + if (m_Actions == null) + { + m_AllMapsHashCode = 0; + return; + } + + int allMapsHashCode = 0; + foreach (var actionMap in m_Actions.actionMaps) + { + allMapsHashCode ^= actionMap.GetHashCode(); + } + if (m_AllMapsHashCode != allMapsHashCode) + { + InstallOnActionTriggeredHook(); + CacheMessageNames(); + m_AllMapsHashCode = allMapsHashCode; + } + } + /// /// Disable input on the player, by disabling the current action map /// @@ -1515,6 +1542,8 @@ private void CacheMessageNames() private void ClearCaches() { + if (m_ActionMessageNames != null) + m_ActionMessageNames.Clear(); } ///