Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

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
  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:
    59
    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!