Search Unity

Character selection

Discussion in 'Multiplayer' started by Goldiedog123, Jul 4, 2017.

  1. Goldiedog123

    Goldiedog123

    Joined:
    Feb 28, 2017
    Posts:
    12
    Hey I'm using the unity lobby asset (the one in the asset store).

    I have edited it so players can click a button and choose what character they would like to be (changes prefab).

    This is fine as it works but clients cant choose a prefab they get given the same one as the host... Any help / ideas would be great. Been on this for like 4 weeks....

    Thanks alot if someone responds!

    CODE:
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.UI;
    4. using UnityEngine.SceneManagement;
    5. using UnityEngine.Networking;
    6. using UnityEngine.Networking.Types;
    7. using UnityEngine.Networking.Match;
    8. using System.Collections;
    9. using UnityEngine.Networking.NetworkSystem;
    10.  
    11. namespace Prototype.NetworkLobby
    12. {
    13.     public class LobbyManager : NetworkLobbyManager
    14.     {
    15.  
    16.         public Button player1Button;
    17.         public Button player2Button;
    18.  
    19.         int avatarIndex = 0;
    20.  
    21.         public Canvas characterSelectionCanvas;
    22.  
    23.  
    24.         static short MsgKicked = MsgType.Highest + 1;
    25.  
    26.         static public LobbyManager s_Singleton;
    27.  
    28.  
    29.         [Header("Unity UI Lobby")]
    30.         [Tooltip("Time in second between all players ready & match start")]
    31.         public float prematchCountdown = 5.0f;
    32.  
    33.         [Space]
    34.         [Header("UI Reference")]
    35.         public LobbyTopPanel topPanel;
    36.  
    37.         public RectTransform mainMenuPanel;
    38.         public RectTransform lobbyPanel;
    39.  
    40.         public LobbyInfoPanel infoPanel;
    41.         public LobbyCountdownPanel countdownPanel;
    42.         public GameObject addPlayerButton;
    43.  
    44.         protected RectTransform currentPanel;
    45.  
    46.         public Button backButton;
    47.  
    48.         public Text statusInfo;
    49.         public Text hostInfo;
    50.  
    51.         //Client numPlayers from NetworkManager is always 0, so we count (throught connect/destroy in LobbyPlayer) the number
    52.         //of players, so that even client know how many player there is.
    53.         [HideInInspector]
    54.         public int _playerNumber = 0;
    55.  
    56.  
    57.         //used to disconnect a client properly when exiting the matchmaker
    58.         [HideInInspector]
    59.         public bool _isMatchmaking = false;
    60.  
    61.         protected bool _disconnectServer = false;
    62.  
    63.         protected ulong _currentMatchID;
    64.  
    65.         protected LobbyHook _lobbyHooks;
    66.  
    67.         void Start()
    68.         {
    69.             s_Singleton = this;
    70.             _lobbyHooks = GetComponent<Prototype.NetworkLobby.LobbyHook>();
    71.             currentPanel = mainMenuPanel;
    72.  
    73.             backButton.gameObject.SetActive(false);
    74.             GetComponent<Canvas>().enabled = true;
    75.  
    76.             DontDestroyOnLoad(gameObject);
    77.  
    78.             player1Button.onClick.AddListener(delegate { AvatarPicker(player1Button.name); });
    79.             player2Button.onClick.AddListener(delegate { AvatarPicker(player2Button.name); });
    80.  
    81.             SetServerInfo("Offline", "None");
    82.         }
    83.  
    84.         void AvatarPicker(string buttonName)
    85.         {
    86.                 switch (buttonName)
    87.                 {
    88.                     case "Player1":
    89.                         avatarIndex = 0;
    90.                         break;
    91.                     case "Player2":
    92.                         avatarIndex = 1;
    93.                         break;
    94.  
    95.                 }
    96.  
    97.                 playerPrefab = spawnPrefabs[avatarIndex];
    98.                 gamePlayerPrefab = spawnPrefabs[avatarIndex];
    99.             }
    100.        
    101.  
    102.         public override void OnLobbyClientSceneChanged(NetworkConnection conn)
    103.         {
    104.             if (SceneManager.GetSceneAt(0).name == lobbyScene)
    105.             {
    106.                 if (topPanel.isInGame)
    107.                 {
    108.                     ChangeTo(lobbyPanel);
    109.                     if (_isMatchmaking)
    110.                     {
    111.                         if (conn.playerControllers[0].unetView.isServer)
    112.                         {
    113.                             backDelegate = StopHostClbk;
    114.                         }
    115.                         else
    116.                         {
    117.                             backDelegate = StopClientClbk;
    118.                         }
    119.                     }
    120.                     else
    121.                     {
    122.                         if (conn.playerControllers[0].unetView.isClient)
    123.                         {
    124.                             backDelegate = StopHostClbk;
    125.                         }
    126.                         else
    127.                         {
    128.                             backDelegate = StopClientClbk;
    129.                         }
    130.                     }
    131.                 }
    132.                 else
    133.                 {
    134.                     ChangeTo(mainMenuPanel);
    135.                 }
    136.  
    137.                 topPanel.ToggleVisibility(true);
    138.                 topPanel.isInGame = false;
    139.             }
    140.             else
    141.             {
    142.                 ChangeTo(null);
    143.  
    144.                 Destroy(GameObject.Find("MainMenuUI(Clone)"));
    145.  
    146.                 //backDelegate = StopGameClbk;
    147.                 topPanel.isInGame = true;
    148.                 topPanel.ToggleVisibility(false);
    149.             }
    150.         }
    151.  
    152.         public void ChangeTo(RectTransform newPanel)
    153.         {
    154.             if (currentPanel != null)
    155.             {
    156.                 currentPanel.gameObject.SetActive(false);
    157.             }
    158.  
    159.             if (newPanel != null)
    160.             {
    161.                 newPanel.gameObject.SetActive(true);
    162.             }
    163.  
    164.             currentPanel = newPanel;
    165.  
    166.             if (currentPanel != mainMenuPanel)
    167.             {
    168.                 backButton.gameObject.SetActive(true);
    169.             }
    170.             else
    171.             {
    172.                 backButton.gameObject.SetActive(false);
    173.                 SetServerInfo("Offline", "None");
    174.                 _isMatchmaking = false;
    175.             }
    176.         }
    177.  
    178.         public void DisplayIsConnecting()
    179.         {
    180.             var _this = this;
    181.             infoPanel.Display("Connecting...", "Cancel", () => { _this.backDelegate(); });
    182.         }
    183.  
    184.         public void SetServerInfo(string status, string host)
    185.         {
    186.             statusInfo.text = status;
    187.             hostInfo.text = host;
    188.         }
    189.  
    190.  
    191.         public delegate void BackButtonDelegate();
    192.         public BackButtonDelegate backDelegate;
    193.         public void GoBackButton()
    194.         {
    195.             backDelegate();
    196.             topPanel.isInGame = false;
    197.         }
    198.  
    199.         // ----------------- Server management
    200.  
    201.         public void AddLocalPlayer()
    202.         {
    203.             TryToAddPlayer();
    204.         }
    205.  
    206.         public void RemovePlayer(LobbyPlayer player)
    207.         {
    208.             player.RemovePlayer();
    209.         }
    210.  
    211.         public void SimpleBackClbk()
    212.         {
    213.             ChangeTo(mainMenuPanel);
    214.         }
    215.  
    216.         public void StopHostClbk()
    217.         {
    218.             if (_isMatchmaking)
    219.             {
    220.                 matchMaker.DestroyMatch((NetworkID)_currentMatchID, 0, OnDestroyMatch);
    221.                 _disconnectServer = true;
    222.             }
    223.             else
    224.             {
    225.                 StopHost();
    226.             }
    227.  
    228.  
    229.             ChangeTo(mainMenuPanel);
    230.         }
    231.  
    232.         public void StopClientClbk()
    233.         {
    234.             StopClient();
    235.  
    236.             if (_isMatchmaking)
    237.             {
    238.                 StopMatchMaker();
    239.             }
    240.  
    241.             ChangeTo(mainMenuPanel);
    242.         }
    243.  
    244.         public void StopServerClbk()
    245.         {
    246.             StopServer();
    247.             ChangeTo(mainMenuPanel);
    248.         }
    249.  
    250.         class KickMsg : MessageBase { }
    251.         public void KickPlayer(NetworkConnection conn)
    252.         {
    253.             conn.Send(MsgKicked, new KickMsg());
    254.         }
    255.  
    256.  
    257.  
    258.  
    259.         public void KickedMessageHandler(NetworkMessage netMsg)
    260.         {
    261.             infoPanel.Display("Kicked by Server", "Close", null);
    262.             netMsg.conn.Disconnect();
    263.         }
    264.  
    265.         //===================
    266.  
    267.         public override void OnStartHost()
    268.         {
    269.             base.OnStartHost();
    270.  
    271.             ChangeTo(lobbyPanel);
    272.             backDelegate = StopHostClbk;
    273.             SetServerInfo("Hosting", networkAddress);
    274.         }
    275.  
    276.         public override void OnMatchCreate(bool success, string extendedInfo, MatchInfo matchInfo)
    277.         {
    278.             base.OnMatchCreate(success, extendedInfo, matchInfo);
    279.             _currentMatchID = (System.UInt64)matchInfo.networkId;
    280.         }
    281.  
    282.         public override void OnDestroyMatch(bool success, string extendedInfo)
    283.         {
    284.             base.OnDestroyMatch(success, extendedInfo);
    285.             if (_disconnectServer)
    286.             {
    287.                 StopMatchMaker();
    288.                 StopHost();
    289.             }
    290.         }
    291.  
    292.         //allow to handle the (+) button to add/remove player
    293.         public void OnPlayersNumberModified(int count)
    294.         {
    295.             _playerNumber += count;
    296.  
    297.             int localPlayerCount = 0;
    298.             foreach (PlayerController p in ClientScene.localPlayers)
    299.                 localPlayerCount += (p == null || p.playerControllerId == -1) ? 0 : 1;
    300.  
    301.             addPlayerButton.SetActive(localPlayerCount < maxPlayersPerConnection && _playerNumber < maxPlayers);
    302.         }
    303.  
    304.         // ----------------- Server callbacks ------------------
    305.  
    306.         //we want to disable the button JOIN if we don't have enough player
    307.         //But OnLobbyClientConnect isn't called on hosting player. So we override the lobbyPlayer creation
    308.         public override GameObject OnLobbyServerCreateLobbyPlayer(NetworkConnection conn, short playerControllerId)
    309.         {
    310.             GameObject obj = Instantiate(lobbyPlayerPrefab.gameObject) as GameObject;
    311.  
    312.             LobbyPlayer newPlayer = obj.GetComponent<LobbyPlayer>();
    313.             newPlayer.ToggleJoinButton(numPlayers + 1 >= minPlayers);
    314.  
    315.  
    316.             for (int i = 0; i < lobbySlots.Length; ++i)
    317.             {
    318.                 LobbyPlayer p = lobbySlots[i] as LobbyPlayer;
    319.  
    320.                 if (p != null)
    321.                 {
    322.                     p.RpcUpdateRemoveButton();
    323.                     p.ToggleJoinButton(numPlayers + 1 >= minPlayers);
    324.                 }
    325.             }
    326.  
    327.             return obj;
    328.         }
    329.  
    330.         public override void OnLobbyServerPlayerRemoved(NetworkConnection conn, short playerControllerId)
    331.         {
    332.             for (int i = 0; i < lobbySlots.Length; ++i)
    333.             {
    334.                 LobbyPlayer p = lobbySlots[i] as LobbyPlayer;
    335.  
    336.                 if (p != null)
    337.                 {
    338.                     p.RpcUpdateRemoveButton();
    339.                     p.ToggleJoinButton(numPlayers + 1 >= minPlayers);
    340.                 }
    341.             }
    342.         }
    343.  
    344.         public override void OnLobbyServerDisconnect(NetworkConnection conn)
    345.         {
    346.             for (int i = 0; i < lobbySlots.Length; ++i)
    347.             {
    348.                 LobbyPlayer p = lobbySlots[i] as LobbyPlayer;
    349.  
    350.                 if (p != null)
    351.                 {
    352.                     p.RpcUpdateRemoveButton();
    353.                     p.ToggleJoinButton(numPlayers >= minPlayers);
    354.                 }
    355.             }
    356.  
    357.         }
    358.  
    359.         public override bool OnLobbyServerSceneLoadedForPlayer(GameObject lobbyPlayer, GameObject gamePlayer)
    360.         {
    361.  
    362.             //This hook allows you to apply state data from the lobby-player to the game-player
    363.             //just subclass "LobbyHook" and add it to the lobby object.
    364.  
    365.             if (_lobbyHooks)
    366.                 _lobbyHooks.OnLobbyServerSceneLoadedForPlayer(this, lobbyPlayer, gamePlayer);
    367.  
    368.  
    369.             return true;
    370.         }
    371.        
    372.         // --- Countdown management
    373.  
    374.         public override void OnLobbyServerPlayersReady()
    375.         {
    376.             bool allready = true;
    377.             for (int i = 0; i < lobbySlots.Length; ++i)
    378.             {
    379.                 if (lobbySlots[i] != null)
    380.                     allready &= lobbySlots[i].readyToBegin;
    381.             }
    382.  
    383.             if (allready)
    384.                 StartCoroutine(ServerCountdownCoroutine());
    385.         }
    386.  
    387.         public IEnumerator ServerCountdownCoroutine()
    388.         {
    389.             float remainingTime = prematchCountdown;
    390.             int floorTime = Mathf.FloorToInt(remainingTime);
    391.  
    392.             while (remainingTime > 0)
    393.             {
    394.                 yield return null;
    395.  
    396.                 remainingTime -= Time.deltaTime;
    397.                 int newFloorTime = Mathf.FloorToInt(remainingTime);
    398.  
    399.                 if (newFloorTime != floorTime)
    400.                 {//to avoid flooding the network of message, we only send a notice to client when the number of plain seconds change.
    401.                     floorTime = newFloorTime;
    402.  
    403.                     for (int i = 0; i < lobbySlots.Length; ++i)
    404.                     {
    405.                         if (lobbySlots[i] != null)
    406.                         {//there is maxPlayer slots, so some could be == null, need to test it before accessing!
    407.                             (lobbySlots[i] as LobbyPlayer).RpcUpdateCountdown(floorTime);
    408.                         }
    409.                     }
    410.                 }
    411.             }
    412.  
    413.             for (int i = 0; i < lobbySlots.Length; ++i)
    414.             {
    415.                 if (lobbySlots[i] != null)
    416.                 {
    417.                     (lobbySlots[i] as LobbyPlayer).RpcUpdateCountdown(0);
    418.                 }
    419.             }
    420.  
    421.             ServerChangeScene(playScene);
    422.         }
    423.  
    424.         // ----------------- Client callbacks ------------------
    425.         public override void OnClientConnect(NetworkConnection conn)
    426.         {
    427.  
    428.             IntegerMessage msg = new IntegerMessage(avatarIndex);
    429.  
    430.             base.OnClientConnect(conn);
    431.  
    432.             infoPanel.gameObject.SetActive(false);
    433.  
    434.             conn.RegisterHandler(MsgKicked, KickedMessageHandler);
    435.  
    436.             if (!NetworkServer.active)
    437.             {//only to do on pure client (not self hosting client)
    438.  
    439.                 ChangeTo(lobbyPanel);
    440.                 backDelegate = StopClientClbk;
    441.                 SetServerInfo("Client", networkAddress);
    442.             }
    443.         }
    444.  
    445.  
    446.         public override void OnClientDisconnect(NetworkConnection conn)
    447.         {
    448.             base.OnClientDisconnect(conn);
    449.             ChangeTo(mainMenuPanel);
    450.         }
    451.  
    452.         public override void OnClientError(NetworkConnection conn, int errorCode)
    453.         {
    454.             ChangeTo(mainMenuPanel);
    455.             infoPanel.Display("Cient error : " + (errorCode == 6 ? "timeout" : errorCode.ToString()), "Close", null);
    456.         }
    457.     }
    458. }
    459.  
     
  2. TwoTen

    TwoTen

    Joined:
    May 25, 2016
    Posts:
    1,168
    The server is the one to spawn the player. So it you can't just change the prefab client sided.
    What I would do is to spawn some temporary player. Like a player object with only a camera. Then send over the character you want to the server once the game has started. Then replace the player object with a new one.
    https://docs.unity3d.com/ScriptReference/Networking.NetworkServer.ReplacePlayerForConnection.html
     
  3. Goldiedog123

    Goldiedog123

    Joined:
    Feb 28, 2017
    Posts:
    12
    I have started trying this ahaha I made the player prefab spawn an empty object with a UI that has 2 options etc.... for the characters. But I don't know how to spawn them once they are clicked...

    ill try to figure out this replace player but you have any other clues?

    BTW THANKS VERY MUCH FOR RESPONDING!
     
  4. TwoTen

    TwoTen

    Joined:
    May 25, 2016
    Posts:
    1,168
    Elaborate?
    My idea was to have a generic player object with nothing other than a script and a camera on. And In the script on the start method you basically replace the object with the selected character.

    Just one way to do it.

    EDIT: I understand what you mean now.
    In the button presses, you want to call a command. In the command you want to spawn the character. Then you want to use the ReplacePlayerForConnection to make that the active player.
     
  5. Goldiedog123

    Goldiedog123

    Joined:
    Feb 28, 2017
    Posts:
    12
    I have a function:
    Code (CSharp):
    1.  
    2.     [Command]
    3.     void CmdReplaceMe(GameObject Player1Object)
    4.     {
    5.         NetworkServer.Spawn(Player1Object);
    6.         NetworkServer.ReplacePlayerForConnection(connectionToClient, Player1Object, playerControllerId);
    7.  
    8.     }
    9.  
    I then in the button click function:
    Code (CSharp):
    1.  
    2.     public void character1click()
    3.     {
    4.         // play that other function
    5.         Destroy(PlayerSpawn);
    6.     }
    7.  
     
  6. TwoTen

    TwoTen

    Joined:
    May 25, 2016
    Posts:
    1,168
    You have to instantiate the object on the server then spawn it also on server.
    You cant instantiate on Client and expect it to be on the server.
     
  7. Goldiedog123

    Goldiedog123

    Joined:
    Feb 28, 2017
    Posts:
    12
    Code (CSharp):
    1.  
    2.     [Command]
    3.     void CmdReplacePlayer(GameObject PlayerPrefab)
    4.     {
    5.         Network.Instantiate(PlayerPrefab, transform.position, transform.rotation, 0);
    6.         NetworkServer.ReplacePlayerForConnection(connectionToClient, PlayerPrefab, playerControllerId);
    7.  
    Thats it isn't it? Also thanks for your time, this is helping a lot.
     
  8. TwoTen

    TwoTen

    Joined:
    May 25, 2016
    Posts:
    1,168
    uhm. You should probably read up the documentation a bit more about how UNET works.
    But here is ish how you would do it. Then you need to pass a int or something to the command and replace the prefab with a Array of prefabs where the int is the index that the client wants.

    Code (CSharp):
    1.     [Command]
    2.     void Cmd_ReplacePlayer()
    3.     {
    4.         //Player prefab is a global variable that refers to a prefab.
    5.      
    6.      
    7.         //This line spawns the prefab just like any signle player game on the server.
    8.         GameObject go = Instantiate(PlayerPrefab, transform.position, transform.rotaion);
    9.         //Then this just tells all the clients to spawn the same object.
    10.         NetworkServer.Spawn(go);
    11.         //Then we try to replace it. And if it succeeded.
    12.         if(NetworkServer.ReplacePlayerForConnection(connectionToClient, go, playerControllerId))
    13.         {
    14.             //We destroy the current player across all instances
    15.             NetworkServer.Destroy(gameObject);
    16.         }
    17.     }
     
    Last edited: Jul 5, 2017
  9. Goldiedog123

    Goldiedog123

    Joined:
    Feb 28, 2017
    Posts:
    12
    In the Network manager I have:

    Code (CSharp):
    1. int avatarIndex = 0;
    Code (CSharp):
    1.         void AvatarPicker(string buttonName)
    2.         {
    3.                 switch (buttonName)
    4.                 {
    5.                     case "Player1":
    6.                         avatarIndex = 0;
    7.                         break;
    8.                     case "Player2":
    9.                         avatarIndex = 1;
    10.                         break;
    11.  
    12.                 }
    Code (CSharp):
    1.                 playerPrefab = spawnPrefabs[avatarIndex];
    2.                 gamePlayerPrefab = spawnPrefabs[avatarIndex];

    That makes it so before players are spawned they can pick what class they would like to be. But all clients are the host etc. Is there a way I can take that number from that code and put it in the spawn code:

    Code (CSharp):
    1. [Command]
    2. void Cmd_ReplacePlayer()
    3. {
    4.     //Player prefab is a global variable that refers to a prefab.
    5.  
    6.  
    7.     //This line spawns the prefab just like any signle player game on the server.
    8.     GameObject go = Instantiate(PlayerPrefab, transform.position, transform.rotaion);
    9.     //Then this just tells all the clients to spawn the same object.
    10.     NetworkServer.Spawn(go);
    11.     //Then we try to replace it. And if it succeeded.
    12.     if (NetworkServer.ReplacePlayerForConnection(connectionToClient, go, playerControllerId))
    13.     {
    14.         //We destroy the current player across all instances
    15.         NetworkServer.Destroy(gameObject);
    16.     }
    17. }
     
  10. TwoTen

    TwoTen

    Joined:
    May 25, 2016
    Posts:
    1,168
    Just make an array of all the player prefabs on the script I corrected for you. Then pass the index you would like as a argument to the command.
    Atleast that's one way to do it.
     
  11. jesse2121

    jesse2121

    Joined:
    Apr 14, 2016
    Posts:
    1
    where do I need to put this code? on an emptyObject in the scene I want to spawn, or do I need to set this script on a prefab and set it as player prefab in the network manager