Skip to content

FIX: Project wide actions enabling actions overrides PlayerInput (ISXB-920) #2144

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Mar 4, 2025

Conversation

ritamerkl
Copy link
Collaborator

@ritamerkl ritamerkl commented Feb 21, 2025

Description

This PR fixes this issue: ISXB-920, where the root cause is that the project wide actions enable all action maps and therefore override the PlayerInput settings.

Major changes:

  • all action maps other than the current one are disabled in PlayerInput at the time of initialization (this resets the activated action maps)
  • the action maps only get enabled if there is not already enabled action in the action map for the project wide action asset, this avoids losing configurations and fixes setting the action maps enabled after PlayerInput initialized (which is a timing issue and seemed to have changed after dc2ce6c875130e0fb8e9077eb48eabd01da75b99.

Testing status & QA

Testing with the client project.

Overall Product Risks

Please rate the potential complexity and halo effect from low to high for the reviewers. Note down potential risks to specific Editor branches if any.

  • Complexity: Low
  • Halo Effect: Medium

Comments to reviewers

To QA: please also test if using the project wide actions works like before, and if the PlayerInput with using different action maps (and in best case also multiple action maps enabled at once) works as expected.

Checklist

Before review:

  • Changelog entry added.
    • Explains the change in Changed, Fixed, Added sections.
    • For API change contains an example snippet and/or migration example.
    • JIRA ticket linked, example (case %%). If it is a private issue, just add the case ID without a link.
    • Jira port for the next release set as "Resolved".
  • Tests added/changed, if applicable.
    • Functional tests Area_CanDoX, Area_CanDoX_EvenIfYIsTheCase, Area_WhenIDoX_AndYHappens_ThisIsTheResult.
    • Performance tests.
    • Integration tests.
  • Docs for new/changed API's.
    • Xmldoc cross references are set correctly.
    • Added explanation how the API works.
    • Usage code examples added.
    • The manual is updated, if needed.

During merge:

  • Commit message for squash-merge is prefixed with one of the list:
    • NEW: ___.
    • FIX: ___.
    • DOCS: ___.
    • CHANGE: ___.
    • RELEASE: 1.1.0-preview.3.

After merge:

  • Create forward/backward port if needed. If you are blocked from creating a forward port now please add a task to ISX-1444.

Copy link
Collaborator

@ekcoh ekcoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes/fix looks good to me @ritamerkl. I think auto-enabling action maps for Project-wide input actions might cause more issues than it solves generally. For this fix, would it be possible to add a test case to make sure we have fixed the bug and avoid future regression?

Copy link
Collaborator

@Pauliusd01 Pauliusd01 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like PWA are enabled whether they're being used or not, is it expected?
https://github.com/user-attachments/assets/3e177cdf-3d46-4dc6-9f13-684a6d1cbe98
In the video I first show off this PR, PWA actions are enabled in the debugger alongside the player input actions I'm using and then show the same thing on current develop

@ritamerkl
Copy link
Collaborator Author

ritamerkl commented Feb 24, 2025

I changed the approach to fix to duplicate the action asset always, since we do not want to operate directly on it, but on a copy for PlayerInput. This is the case for project wide action assets as well as for assets that are used for the UIInputModule or elsewhere. This should fix the issues you mentioned @Pauliusd01.
I would appreciate a second round of review with the latest changes @ekcoh.

@ritamerkl
Copy link
Collaborator Author

Hold back with testing / reviews for now, WIP

@ritamerkl ritamerkl marked this pull request as draft February 24, 2025 15:00
@ritamerkl ritamerkl marked this pull request as ready for review February 25, 2025 12:48
Copy link
Collaborator

@ekcoh ekcoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes seem to be in line with what we discussed, some minor questions I hope we can sort out but approving anyway.

Assert.That(actions["UI/Navigate"].controls, Is.Empty);
Assert.That(actions["UI/Point"].controls, Is.EquivalentTo(new[] { mouse.position }));
Assert.That(actions["UI/Click"].controls, Is.EquivalentTo(new[] { mouse.leftButton }));
Assert.That(player.actions.FindActionMap("Gameplay").enabled, Is.True);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe insert a new line after this one and add a comment why there is a split now?

@@ -391,12 +392,13 @@ public void PlayerInput_CanAssignActionsToPlayer()
var actions = InputActionAsset.FromJson(kActions);
playerInput.actions = actions;

Assert.That(playerInput.actions, Is.SameAs(actions));
Assert.That(playerInput.actions, !Is.SameAs(actions)); // Should have created a copy.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is dangerous since it would call Equals or any overload, what you really want to check here is ReferenceEquals to make sure its a different instance (some types compare equal even if they are different instances)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

outdated with new commits, replaced with (playerInput.actions.actionMaps[0].name, Is.EqualTo(actions.actionMaps[0].name)

@@ -391,12 +392,13 @@ public void PlayerInput_CanAssignActionsToPlayer()
var actions = InputActionAsset.FromJson(kActions);
playerInput.actions = actions;

Assert.That(playerInput.actions, Is.SameAs(actions));
Assert.That(playerInput.actions, !Is.SameAs(actions)); // Should have created a copy.
Assert.That(playerInput.actions.actionMaps.Count, !Is.SameAs(actions.actionMaps.Count));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused around this assert, what is it proving?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

outdated with new commits, replaced with (playerInput.actions.actionMaps[0].name, Is.EqualTo(actions.actionMaps[0].name)

}

[Test]
[Category("PlayerInput")]
public void PlayerInput_AssigningNewActionsToPlayer_DisablesExistingActions()
public void PlayerInput_AssigningNewActionsToPlayer_LeavingOriginalAssetsUntouched()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to this, what happens when the original asset is modified after being cloned? Is the PlayerInput updated to reflect or just fixed to what it was when instantiated? I am not sure if it intends to monitor that or not...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the original changes it wouldn't reflect in the copies of the PlayerInput actions component. They could only be changed through the playerInput.actions property for a single PlayerInput.
Thinking about it I am less certain if it wouldn't introduce more regression seeing this comment:
// Make sure that no cloning of actions happened on the prefab.
// https://fogbugz.unity3d.com/f/cases/1319756/
Thus I wonder if that is no problem for the other PlayerInput instances, since it will be cloned if more than one player jumps in.

for (var binding = 0; binding < oldActions.actionMaps[actionMap].bindings.Count; binding++)
m_Actions.actionMaps[actionMap].ApplyBindingOverride(binding, oldActions.actionMaps[actionMap].bindings[binding]);
}
// duplicate action asset to not operate on the original(as it might be used outside - eg project wide action asset or UIInputModule)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO this is much cleaner to not let it depend on some condition whether there is a clone or not.

@ritamerkl ritamerkl force-pushed the fix-project-wide-actions-override-playerinput branch from 2281ca6 to b05b5e8 Compare February 27, 2025 16:27
@ritamerkl ritamerkl requested a review from ekcoh February 28, 2025 12:00
Copy link
Collaborator

@ekcoh ekcoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New changes looks good to me.

@@ -342,8 +342,14 @@ public InputActionAsset actions
UninitializeActions();
}

var didChange = m_Actions != null;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is related to your question around comparing InputActionAssets? It's not going to be cheap to compare, but a comparator would be useful. Additionally that comparator could compute a hash to make the comparison cheaper. However, this could also be fine since it will very likely be different if it's another instance. Otherwise the project itself is oddly designed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, all this is around avoiding copying the asset multiple times, which works as far as I tested and for the cases I could come up with, but like you said ideally it would be great to be able to compare an copy of asset to it's original to determine that it's a clone of the asset.

@@ -1430,6 +1429,18 @@ private void InitializeActions()
m_ActionsInitialized = true;
}

private void CopyActionAsset()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rename this CopyActionAssetAndApplyBindingOverrides() since it attempts to preserve binding overrides? I wonder how it actually works though since the new asset might be completely different.... (not new on this PR)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed in ce0a9a5

@Pauliusd01
Copy link
Collaborator

Pauliusd01 commented Mar 3, 2025

Still seeing some odd things with project wide actions getting duplicated.
https://github.com/user-attachments/assets/ac39d5c9-6710-4902-ae19-610f93f98965
In the video I'm using project wide actions for player input with your PR and develop. First showing your PR, it shows project wide actions active in the debugger twice while the develop one does not. Also, I noticed that the actions asset gets the "cloned" tag as well in your version

Copy link
Collaborator

@Pauliusd01 Pauliusd01 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updating status

@ritamerkl
Copy link
Collaborator Author

Still seeing some odd things with project wide actions getting duplicated. https://github.com/user-attachments/assets/ac39d5c9-6710-4902-ae19-610f93f98965 In the video I'm using project wide actions for player input with your PR and develop. First showing your PR, it shows project wide actions active in the debugger twice while the develop one does not.

Yes, that is intended. The project wide actions will be enabled, if the PlayerInput uses the same action asset like the project wide actions, the PlayerInput clone of the asset will be enabled at the same time.

Also, I noticed that the actions asset gets the "cloned" tag as well in your version

Yes, that is due to the fact that the PlayerInput asset is duplicated for the first player now too. But this will reset to the original asset exiting the play mode.

@Pauliusd01 Pauliusd01 self-requested a review March 4, 2025 06:56
@ritamerkl ritamerkl merged commit 7a6cb91 into develop Mar 4, 2025
3 of 94 checks passed
@ritamerkl ritamerkl deleted the fix-project-wide-actions-override-playerinput branch March 4, 2025 18:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants