Search Unity

Resolved PlayerInputManager Only Joins One Player With Shared Controls

Discussion in 'Input System' started by ibbitz, Sep 9, 2020.

  1. ibbitz

    ibbitz

    Joined:
    Sep 8, 2020
    Posts:
    8
    Hello all, this is my first post here so LMK if I need to fix anything.

    Background: I'm working on a multiplayer game with multiple Characters using the New Input System, but can't seem to get player joining to work for the last few days. There isn't much documentation around how to implement this with multiple Characters, so my high-level approach is:
    • Player - manages controller inputs, any other data, persists across scenes and can route events from the PlayerInput to any observer (eg: a Character).
    • PlayerManager - singleton for Players that also manages the join state of a PlayerInputManager.
    • Add a PlayerInputManager to PlayerManager prefab that creates Players
    Issue Description: I am able to only join 1 player using the PlayerInputManager. If I join the first player using KBM (Keyboard + Mouse), and then attempt to join using my Xbox controller, I am able to control a single Player with both inputs, however, the PlayerInput of the Player only lists the first device to join. I have also tested this with a PS4 gamepad and the same issue occurs, so it's not a controller issue either.

    Expected Behavior: KBM and Xbox controller join as separate Players.

    Screenshots:
    InputActionAsset
    upload_2020-9-8_19-37-32.png
    Controller Control Scheme (Gamepad is the only required device)
    upload_2020-9-8_19-38-58.png
    KBM Control Scheme (both devices required)
    upload_2020-9-8_19-39-50.png
    PlayerManager prefab
    upload_2020-9-8_19-40-27.png
    Player Prefab
    upload_2020-9-8_19-40-54.png

    Minified Code:
    PlayerManager.cs
    Code (CSharp):
    1.  
    2. // Class that joins/manages Players through the PlayerInputManager
    3. public class PlayerManager : MonoBehaviour
    4. {
    5.     public InputActionAsset inputActions;
    6.     private PlayerInputManager manager;
    7.  
    8.     // Singleton implementation for simple access
    9.     private PlayerManager() { }
    10.     private static PlayerManager _instance;
    11.     public static PlayerManager Instance() {
    12.         if (_instance == null)
    13.             _instance = FindObjectOfType<PlayerManager>();
    14.         return _instance;
    15.     }
    16.  
    17.     void Start()
    18.     {
    19.         DontDestroyOnLoad(gameObject);
    20.         InitializeManager();
    21.     }
    22.     public void OnPlayerJoined(PlayerInput player)
    23.     {
    24.         InitializeManager();
    25.         player.actions = inputActions;
    26.         if (manager.playerCount >= manager.maxPlayerCount)
    27.             manager.DisableJoining();
    28.     }
    29.     public void OnPlayerLeft(PlayerInput player)
    30.     {
    31.         InitializeManager();
    32.         if (manager.playerCount < manager.maxPlayerCount)
    33.             manager.EnableJoining();
    34.     }
    35.     private void InitializeManager()
    36.     {
    37.         manager = GetComponent<PlayerInputManager>();
    38.     }
    39. }
    40.  
    Player.cs
    Code (CSharp):
    1.  
    2. public class Player : MonoBehaviour
    3. {
    4.     public int port = -1;
    5.     public Character characterPrefab;
    6.     private Character characterInstance;
    7.     private PlayerInput input;
    8.  
    9.     void Start()
    10.     {
    11.         DontDestroyOnLoad(gameObject);
    12.         input = GetComponent<PlayerInput>();
    13.         port = input.playerIndex;
    14.         // TODO: Initialize elsewhere
    15.         BuildCharacter();
    16.     }
    17.     public Character BuildCharacter()
    18.     {
    19.         var charObject = Instantiate(characterPrefab);
    20.         characterInstance = charObject;
    21.         return charObject;
    22.     }
    23.     private string DeviceString()
    24.     {
    25.         var str = "[";
    26.         foreach (var device in input.devices)
    27.         {
    28.             str += device.displayName + ", ";
    29.         }
    30.         str += "]";
    31.         return str;
    32.     }
    33. }
    34.  
    Versions: Unity 2020.1.3f1 Personal, Input System v1.0.0

    Any help on this would be greatly appreciated. I'd really love to get a better idea of what's happening here. This system seems great despite its current limitations, I just wish the joining process was less of a black box in this regard.
     
    Last edited: Sep 10, 2020
    SchGames likes this.
  2. ibbitz

    ibbitz

    Joined:
    Sep 8, 2020
    Posts:
    8
    Bumping this as it's been a few days without response. I've been stuck on this for a couple weeks now and would love to get unblocked. I tried recreating a more simplified InputActionAsset and the same issue arises. I think part of the issue is that when i press an input I get disconnected, rejoin, then reconnect but it's not clear why that's happening?
     
  3. ibbitz

    ibbitz

    Joined:
    Sep 8, 2020
    Posts:
    8
    Update: Still stuck on this.. :(
    I've confirmed this happens on any machine, after rebuilding my dependencies, and have reproduced it on my laptop as well. I added some more verbose logging to OnPlayerJoined and OnPlayerLeft (see below)
    Code (CSharp):
    1.  
    2. public void OnPlayerJoined(PlayerInput player)
    3.     {
    4.         InitializeManager();
    5.         Debug.Log("Joined " + player.playerIndex + " - " + player.devices[0].displayName);
    6.         Debug.Log("Player Count " + manager.playerCount + "/" + manager.maxPlayerCount);
    7.         player.actions = inputActions;
    8.         if (manager.playerCount >= manager.maxPlayerCount  && manager.joiningEnabled)
    9.         {
    10.             manager.DisableJoining();
    11.             Debug.Log("Disabled Join");
    12.         }
    13.     }
    14.     public void OnPlayerLeft(PlayerInput player)
    15.     {
    16.         InitializeManager();
    17.         Debug.Log("Disconnected " + player.playerIndex);
    18.         Debug.Log("Player Count " + manager.playerCount + "/" + manager.maxPlayerCount);
    19.         if (manager.playerCount < manager.maxPlayerCount  && !manager.joiningEnabled)
    20.         {
    21.             manager.EnableJoining();
    22.             Debug.Log("Enabled Join");
    23.         }
    24.     }
    25.  
    With these changes I get the following logs back:
    Pres A on XBOX controller (first log), then click with Mouse (last 3 logs at same time)
    upload_2020-9-25_21-3-6.png
    Click with mouse (first log), then press A with XBOX Controller
    upload_2020-9-25_21-1-19.png
    Based on this, it looks like instead of the PlayerInputManager adding a new Player instance, it instead joins a new PlayerInputManager, fires an event, then immediately disconnects the device.
    Two things here are actually confusing me a lot:
    1. This behavior happens with a max player count of 4, despite only using 3 devices (Mouse + Keyboard, XBOX controller). As you can see from the logs, I never hit the max player count, so I don't get why I would even disable joining in the first place.
    2. The PlayerInputManager documentation says that it should automatically disable joining once maxPlayerCount is reached. But unless I did it manually in PlayerManager, it would give me an error saying max number of players was reached and not disable joining.
     
    Last edited: Sep 26, 2020
  4. ibbitz

    ibbitz

    Joined:
    Sep 8, 2020
    Posts:
    8
    Sorry if I'm spamming this thread. I think I made SOME progress on this, but still unsure what's going on.
    I set the Player's default control scheme from <Any> to Controller, joined with KBM, then joined with my controller and both players spawned. However my controller inputs affected both players. If I join with the controller first, KBM inputs just go to the first player and do not join a second player.
    I'm wondering if maybe this has to do with how the PlayerInputManager handles different control schemes? This behavior is not described anywhere in the PlayerInputManager documentation which is incredibly frustrating.
     
  5. ibbitz

    ibbitz

    Joined:
    Sep 8, 2020
    Posts:
    8
    Well after a month of no response I managed to figure it out on my own. Posting here for future reference. The issue was caused by manually setting the InputActionAsset via
    Code (CSharp):
    1. player.actions = inputActions;
    It seems that when this is set there's a handful of other side effects that are not documented. Why this caused disconnects/reconnects /shared controls though is beyond my grasp. Would love to hear from others why it might be.
     
  6. m4rtin-t

    m4rtin-t

    Joined:
    Jan 30, 2016
    Posts:
    8
    This is not the problem I was trying to look up, but thank you for your 1 month adventure.
     
    ColinPage likes this.
  7. the_jaysaurus

    the_jaysaurus

    Joined:
    Dec 21, 2020
    Posts:
    21
    bad luck that you had to muddle through :( honestly really disappointed in the new system. Documentation is patchy at best (I code for a living and I'd get a lot of flack if I churned out docs of such poor quality in my tech stack) I too am struggling with a similar issue. What a pity.
     
  8. gg_michael

    gg_michael

    Joined:
    Sep 24, 2012
    Posts:
    73
    Very late to this party but wanted to thank you, this thread came up in a google search and you solved my problem. Turned out to be the same thing. Thanks!
     
  9. SchGames

    SchGames

    Joined:
    May 12, 2023
    Posts:
    3
    Same. Knowing that there are people willing to help the others even after so much time of spending on a specific problem, makes this world a better place. Thanks!

    I've stumbled upon this problem when searching for a solution for spawning multiple players when clicking a button to join local coop game. After hours of searching, I found out that my Playstation 4 joystick was using DS4Windows tool and the Unity spawned one player of DS4Windows and one for my Playstation 4 joystick... I've exit the DS4Windows tool and it works perfectly :)
     
  10. snipshotmedia

    snipshotmedia

    Joined:
    Nov 13, 2023
    Posts:
    10
    2 Weeks I was having issues, turns out Steam running in the background was doing the same thing as your DS4Windows tool.

    My biggest issue is how do I get a player prefab to be reused using the Player Input manager, and not just have it pumped out cloned version every time my player is deactivated, and I press a button.

    I can simply add a script to delete the parent when it detects a child has been deactivated but then I lose the assigned player ID which I need for pool manager tracking. What a mess!
     
  11. micahxavier2018

    micahxavier2018

    Joined:
    Dec 1, 2020
    Posts:
    24
    I had a simmilar problem where my ps4 controller would sort of control both players, I then realized Steam was F***ing up the input and trying to remap it so that the controller could "work" on my game.