Input System v1.0 - PlayerInput.Instantiate seems to clone InputActionAsset, causing rebinding issue

Greetings. I have been busy implementing the new Input System in my game.

Here is what I have so far:

  • An InputActionAsset for player controls. There are 2 bindings in each action for Player1 and Player2 control schemes. Each player uses the same InputActionAsset but with different control schemes for each of them. All of the players use the same input device simultaneously, in this case using Keyboard.current.

  • A game manager that instantiates a number of gameobjects from a prefab using PlayerInput.Instantiate. The manager loops through an array of booleans that checks if this player is active, then instantiates into the scene. Control schemes of associated number is assigned to each player.
for (int i = 0; i < active.Length; i++)
        {
            if(active[i]){
                string name = "Player" + (i+1);

                PlayerInput player = PlayerInput.Instantiate(playerPrefab, -1, name, -1, Keyboard.current);
                InputUser.PerformPairingWithDevice(Keyboard.current, player.user, InputUserPairingOptions.None);
                player.defaultControlScheme = name;
            }
        }
  • A rebinding UI menu that allows user to override the default controls for each player. This is taken from the Rebinding UI sample. The menu is prompted using backspace key. When the menu is active, all PlayerInput components are set to disabled, because I encountered an error when I tried to rebind the controls when the PlayerInput is enabled. The PlayerInputs are reenabled when closing.


The issue:

On Play mode, two players are instantiated. I notice that the InputActionAsset for both players are different, with Player2 having a cloned version of PlayerInputAction.

Player1

Player2

Both player controls work normally at first. However, when I tried to rebind the controls, Player1 resumes accordingly with the new key binding, but Player2 remained with its default binding unchanged, although the rebinding UI shows the new key binding.

From the issue, I came to a conclusion that I am overriding the key binding for the original PlayerInputAction, which does not seem to reflect the cloned version in Player2.

Player2 begins to follow the new binding when I manually drag the original PlayerInputAction from the Project directory into the PlayerInput.actions and restore the component (disabling and enabling back). I would want this process to be procedural in code.

I have tried using GameObject version of Instantiate, but the problem still persists.

Perhaps there is a solution or an issue to be resolved? Any help is appreciated.

3 Likes

I get the same problem today, did you find any solution to the problems?

1 Like

I also stumbled upon a similar issue today, and eventually I’ve came up with a solution!

Basically you have an InputActionAsset that gets rebinded, but when you create new PlayerInputs it doesn’t use the rebinded keys. So you need to copy the overriden bindings from the original InputActionAsset into the PlayerInput’s. Below is a way to do it:

private void CopyOverridenBindings(InputActionMap copyActionMap, InputActionMap originalActionMap)
    {
        for (int i = 0; i < copyActionMap.actions.Count; i++)
        {
            var copyAction = copyActionMap.actions[i];
            var originalAction = originalActionMap.actions[i];
            for (int j = 0; j < copyAction.bindings.Count; j++)
            {
                var originalBinding = originalAction.bindings[j];
                if (originalBinding.overridePath != null
                    && originalBinding.overridePath != string.Empty)
                {
                    copyAction.ChangeBinding(j).WithPath(originalBinding.overridePath);
                }
            }
        }
    }

You just have to feed the action maps from PlayerInput and the original InputActionAsset. In my case those are named “Gameplay”.

CopyOverridenBindings(
            playerInput.actions.FindActionMap("Gameplay"),
            InputActions.asset.FindActionMap("Gameplay")
        );

I’m having this same exact problem! For this code you replied with, where did you put this? Are you calling it in an individual script in Update every frame? Or just at Start or Awake? I’ve been dealing with this for probably 20+ hours!

I would seriously even be willing to pay for your help!

I seem to have solved the issue in a stupid way:

Whenever I rebind a key I persist it via

        var rebinds = actions.SaveBindingOverridesAsJson();
        PlayerPrefs.SetString("rebinds", rebinds);

and then I iterate over all my PlayerInputs and reload the bindings

        var input = GetComponent<PlayerInput>();
        var rebinds = PlayerPrefs.GetString("rebinds");
        if (!string.IsNullOrEmpty(rebinds))
            input.actions.LoadBindingOverridesFromJson(rebinds);