Client choice of prefabs on a NetworkLobbyManager
I have a nearly finished game. Using the regular NetworkManager, the player can choose the object they spawn with using a dropdown. However, I would like a lobby before the players spawn in.
Working code for players selecting their own prefabs through UNET Network Manager:
 using UnityEngine;
 using UnityEngine.Networking;
 using UnityEngine.Networking.NetworkSystem;
 
 public class NetLobbyManager : NetworkLobbyManager {
 
     public Transform spawnPosition;   
     public int curPlayer;
 
     public UnityEngine.UI.Dropdown shipDropdownGO;
 
 
     void Update(){
         if(shipDropdownGO != null){
             curPlayer = shipDropdownGO.value;
         }
     }
 
 
 
 
     //Called on client when connect
     public override void OnClientConnect(NetworkConnection conn) {       
 
         // Create message to set the player
         IntegerMessage msg = new IntegerMessage(curPlayer);      
         // Call Add player and pass the message
         ClientScene.AddPlayer(conn,0, msg);
     }
 
     // Server
     public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId, NetworkReader extraMessageReader ) { 
         // Read client message and receive index
         if (extraMessageReader != null) {
             var stream = extraMessageReader.ReadMessage<IntegerMessage> ();
             curPlayer = stream.value;
         }
         //Select the prefab from the spawnable objects list
         var playerPrefab = spawnPrefabs[curPlayer];       
 
         // Create player object with prefab
         var player = Instantiate(playerPrefab, spawnPosition.position, Quaternion.identity) as GameObject;        
 
         // Add player object for connection
         NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
     }
 }
 
               Working code for a lobby manager:
 using UnityEngine;
 using UnityEngine.UI;
 using UnityEngine.SceneManagement;
 using UnityEngine.Networking;
 using UnityEngine.Networking.Types;
 using UnityEngine.Networking.Match;
 using System.Collections;
 
 
 namespace Prototype.NetworkLobby
 {
     public class LobbyManager : NetworkLobbyManager 
     {
         static short MsgKicked = MsgType.Highest + 1;
 
         static public LobbyManager s_Singleton;
 
 
         [Header("Unity UI Lobby")]
         [Tooltip("Time in second between all players ready & match start")]
         public float prematchCountdown = 5.0f;
 
         [Space]
         [Header("UI Reference")]
         public LobbyTopPanel topPanel;
 
         public RectTransform mainMenuPanel;
         public RectTransform lobbyPanel;
 
         public LobbyInfoPanel infoPanel;
         public LobbyCountdownPanel countdownPanel;
         public GameObject addPlayerButton;
 
         protected RectTransform currentPanel;
 
         public Button backButton;
 
         public Text statusInfo;
         public Text hostInfo;
 
         //Client numPlayers from NetworkManager is always 0, so we count (throught connect/destroy in LobbyPlayer) the number
         //of players, so that even client know how many player there is.
         [HideInInspector]
         public int _playerNumber = 0;
 
         //used to disconnect a client properly when exiting the matchmaker
         [HideInInspector]
         public bool _isMatchmaking = false;
 
         protected bool _disconnectServer = false;
         
         protected ulong _currentMatchID;
 
         protected LobbyHook _lobbyHooks;
 
         void Start()
         {
             s_Singleton = this;
             _lobbyHooks = GetComponent<Prototype.NetworkLobby.LobbyHook>();
             currentPanel = mainMenuPanel;
 
             backButton.gameObject.SetActive(false);
             GetComponent<Canvas>().enabled = true;
 
             DontDestroyOnLoad(gameObject);
 
             SetServerInfo("Offline", "None");
         }
 
         public override void OnLobbyClientSceneChanged(NetworkConnection conn)
         {
             if (SceneManager.GetSceneAt(0).name == lobbyScene)
             {
                 if (topPanel.isInGame)
                 {
                     ChangeTo(lobbyPanel);
                     if (_isMatchmaking)
                     {
                         if (conn.playerControllers[0].unetView.isServer)
                         {
                             backDelegate = StopHostClbk;
                         }
                         else
                         {
                             backDelegate = StopClientClbk;
                         }
                     }
                     else
                     {
                         if (conn.playerControllers[0].unetView.isClient)
                         {
                             backDelegate = StopHostClbk;
                         }
                         else
                         {
                             backDelegate = StopClientClbk;
                         }
                     }
                 }
                 else
                 {
                     ChangeTo(mainMenuPanel);
                 }
 
                 topPanel.ToggleVisibility(true);
                 topPanel.isInGame = false;
             }
             else
             {
                 ChangeTo(null);
 
                 Destroy(GameObject.Find("MainMenuUI(Clone)"));
 
                 //backDelegate = StopGameClbk;
                 topPanel.isInGame = true;
                 topPanel.ToggleVisibility(false);
             }
         }
 
         public void ChangeTo(RectTransform newPanel)
         {
             if (currentPanel != null)
             {
                 currentPanel.gameObject.SetActive(false);
             }
 
             if (newPanel != null)
             {
                 newPanel.gameObject.SetActive(true);
             }
 
             currentPanel = newPanel;
 
             if (currentPanel != mainMenuPanel)
             {
                 backButton.gameObject.SetActive(true);
             }
             else
             {
                 backButton.gameObject.SetActive(false);
                 SetServerInfo("Offline", "None");
                 _isMatchmaking = false;
             }
         }
 
         public void DisplayIsConnecting()
         {
             var _this = this;
             infoPanel.Display("Connecting...", "Cancel", () => { _this.backDelegate(); });
         }
 
         public void SetServerInfo(string status, string host)
         {
             statusInfo.text = status;
             hostInfo.text = host;
         }
 
 
         public delegate void BackButtonDelegate();
         public BackButtonDelegate backDelegate;
         public void GoBackButton()
         {
             backDelegate();
             topPanel.isInGame = false;
         }
 
         // ----------------- Server management
 
         public void AddLocalPlayer()
         {
             TryToAddPlayer();
         }
 
         public void RemovePlayer(LobbyPlayer player)
         {
             player.RemovePlayer();
         }
 
         public void SimpleBackClbk()
         {
             ChangeTo(mainMenuPanel);
         }
                  
         public void StopHostClbk()
         {
             if (_isMatchmaking)
             {
                 matchMaker.DestroyMatch((NetworkID)_currentMatchID, 0, OnDestroyMatch);
                 _disconnectServer = true;
             }
             else
             {
                 StopHost();
             }
 
             
             ChangeTo(mainMenuPanel);
         }
 
         public void StopClientClbk()
         {
             StopClient();
 
             if (_isMatchmaking)
             {
                 StopMatchMaker();
             }
 
             ChangeTo(mainMenuPanel);
         }
 
         public void StopServerClbk()
         {
             StopServer();
             ChangeTo(mainMenuPanel);
         }
 
         class KickMsg : MessageBase { }
         public void KickPlayer(NetworkConnection conn)
         {
             conn.Send(MsgKicked, new KickMsg());
         }
 
 
 
 
         public void KickedMessageHandler(NetworkMessage netMsg)
         {
             infoPanel.Display("Kicked by Server", "Close", null);
             netMsg.conn.Disconnect();
         }
 
         //===================
 
         public override void OnStartHost()
         {
             base.OnStartHost();
 
             ChangeTo(lobbyPanel);
             backDelegate = StopHostClbk;
             SetServerInfo("Hosting", networkAddress);
         }
 
         public override void OnMatchCreate(bool success, string extendedInfo, MatchInfo matchInfo)
         {
             base.OnMatchCreate(success, extendedInfo, matchInfo);
             _currentMatchID = (System.UInt64)matchInfo.networkId;
         }
 
         public override void OnDestroyMatch(bool success, string extendedInfo)
         {
             base.OnDestroyMatch(success, extendedInfo);
             if (_disconnectServer)
             {
                 StopMatchMaker();
                 StopHost();
             }
         }
 
         //allow to handle the (+) button to add/remove player
         public void OnPlayersNumberModified(int count)
         {
             _playerNumber += count;
 
             int localPlayerCount = 0;
             foreach (PlayerController p in ClientScene.localPlayers)
                 localPlayerCount += (p == null || p.playerControllerId == -1) ? 0 : 1;
 
             addPlayerButton.SetActive(localPlayerCount < maxPlayersPerConnection && _playerNumber < maxPlayers);
         }
 
         // ----------------- Server callbacks ------------------
 
         //we want to disable the button JOIN if we don't have enough player
         //But OnLobbyClientConnect isn't called on hosting player. So we override the lobbyPlayer creation
         public override GameObject OnLobbyServerCreateLobbyPlayer(NetworkConnection conn, short playerControllerId)
         {
             GameObject obj = Instantiate(lobbyPlayerPrefab.gameObject) as GameObject;
 
             LobbyPlayer newPlayer = obj.GetComponent<LobbyPlayer>();
             newPlayer.ToggleJoinButton(numPlayers + 1 >= minPlayers);
 
 
             for (int i = 0; i < lobbySlots.Length; ++i)
             {
                 LobbyPlayer p = lobbySlots[i] as LobbyPlayer;
 
                 if (p != null)
                 {
                     p.RpcUpdateRemoveButton();
                     p.ToggleJoinButton(numPlayers + 1 >= minPlayers);
                 }
             }
 
             return obj;
         }
 
         public override void OnLobbyServerPlayerRemoved(NetworkConnection conn, short playerControllerId)
         {
             for (int i = 0; i < lobbySlots.Length; ++i)
             {
                 LobbyPlayer p = lobbySlots[i] as LobbyPlayer;
 
                 if (p != null)
                 {
                     p.RpcUpdateRemoveButton();
                     p.ToggleJoinButton(numPlayers + 1 >= minPlayers);
                 }
             }
         }
 
         public override void OnLobbyServerDisconnect(NetworkConnection conn)
         {
             for (int i = 0; i < lobbySlots.Length; ++i)
             {
                 LobbyPlayer p = lobbySlots[i] as LobbyPlayer;
 
                 if (p != null)
                 {
                     p.RpcUpdateRemoveButton();
                     p.ToggleJoinButton(numPlayers >= minPlayers);
                 }
             }
 
         }
 
         public override bool OnLobbyServerSceneLoadedForPlayer(GameObject lobbyPlayer, GameObject gamePlayer)
         {
             //This hook allows you to apply state data from the lobby-player to the game-player
             //just subclass "LobbyHook" and add it to the lobby object.
 
             if (_lobbyHooks)
                 _lobbyHooks.OnLobbyServerSceneLoadedForPlayer(this, lobbyPlayer, gamePlayer);
 
             return true;
         }
 
 
 
 
 
 
 
 
 
         // --- Countdown management
 
         public override void OnLobbyServerPlayersReady()
         {
             bool allready = true;
             for(int i = 0; i < lobbySlots.Length; ++i)
             {
                 if(lobbySlots[i] != null)
                     allready &= lobbySlots[i].readyToBegin;
             }
 
             if(allready)
                 StartCoroutine(ServerCountdownCoroutine());
         }
 
         public IEnumerator ServerCountdownCoroutine()
         {
             float remainingTime = prematchCountdown;
             int floorTime = Mathf.FloorToInt(remainingTime);
 
             while (remainingTime > 0)
             {
                 yield return null;
 
                 remainingTime -= Time.deltaTime;
                 int newFloorTime = Mathf.FloorToInt(remainingTime);
 
                 if (newFloorTime != floorTime)
                 {//to avoid flooding the network of message, we only send a notice to client when the number of plain seconds change.
                     floorTime = newFloorTime;
 
                     for (int i = 0; i < lobbySlots.Length; ++i)
                     {
                         if (lobbySlots[i] != null)
                         {//there is maxPlayer slots, so some could be == null, need to test it before accessing!
                             (lobbySlots[i] as LobbyPlayer).RpcUpdateCountdown(floorTime);
                         }
                     }
                 }
             }
 
             for (int i = 0; i < lobbySlots.Length; ++i)
             {
                 if (lobbySlots[i] != null)
                 {
                     (lobbySlots[i] as LobbyPlayer).RpcUpdateCountdown(0);
                 }
             }
 
             ServerChangeScene(playScene);
         }
 
         // ----------------- Client callbacks ------------------
 
         public override void OnClientConnect(NetworkConnection conn)
         {
             base.OnClientConnect(conn);
 
             infoPanel.gameObject.SetActive(false);
 
             conn.RegisterHandler(MsgKicked, KickedMessageHandler);
 
             if (!NetworkServer.active)
             {//only to do on pure client (not self hosting client)
                 ChangeTo(lobbyPanel);
                 backDelegate = StopClientClbk;
                 SetServerInfo("Client", networkAddress);
             }
         }
 
 
         public override void OnClientDisconnect(NetworkConnection conn)
         {
             base.OnClientDisconnect(conn);
             ChangeTo(mainMenuPanel);
         }
 
         public override void OnClientError(NetworkConnection conn, int errorCode)
         {
             ChangeTo(mainMenuPanel);
             infoPanel.Display("Cient error : " + (errorCode == 6 ? "timeout" : errorCode.ToString()), "Close", null);
         }
     }
 }
 
 
               My issue is if I transpose the code into the "same" places, it compiles and runs just fine, but the player selected objects spawn into the lobby, not the following scene. I cannot find a working example of how to accomplish this online nor can I find any documentation that makes any sense.
This code enabled me to spawn the chosen prefabs but also spawned duplicates. I can't figure out how to prevent the duplicates being generated as I have no idea what is generating them and as such no idea what to attempt to override or what to replace it with. https://forum.unity3d.com/threads/network-lobby-manager-spawn-selected-prefab-for-client.376484/
Please, please, somebody have a solution.
Your answer
 
             Follow this Question
Related Questions
Unity 5 Unet Network Rigidbody Syncing - Client sinking through objects. 0 Answers
Client Spawning Player Objects 0 Answers
Networking best practices for handling local player 0 Answers
Problem spawning prefabs client side, stand alone build. 0 Answers
Networking: How to access local client's owned objects? 0 Answers