Unity Lobby Multiplayer, multiple player prefabs

Hi all before I ask my question ill show my code… it sort of works. BTW the code is the unity LobbyManager script with a few edits for multiple player prefabs.

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
    {

        public Button player1Button;
        public Button player2Button;

        int avatarIndex = 0;

        public Canvas characterSelectionCanvas;


        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);

            player1Button.onClick.AddListener(delegate { AvatarPicker(player1Button.name); });
            player2Button.onClick.AddListener(delegate { AvatarPicker(player2Button.name); });

            SetServerInfo("Offline", "None");
        }

        void AvatarPicker(string buttonName)
        {
            switch (buttonName)
            {
                case "Player1":
                    avatarIndex = 0;
                    break;
                case "Player2":
                    avatarIndex = 1;
                    break;

            }

            playerPrefab = spawnPrefabs[avatarIndex];
            gamePlayerPrefab = spawnPrefabs[avatarIndex];
        }


        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 *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 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 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 != null)
allready &= lobbySlots*.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 != null)
{//there is maxPlayer slots, so some could be == null, need to test it before accessing!
(lobbySlots as LobbyPlayer).RpcUpdateCountdown(floorTime);
}
}
}
}

for (int i = 0; i < lobbySlots.Length; ++i)
{
if (lobbySlots != null)
{
(lobbySlots 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);
}
}
}

OK SO. When you click the buttons it changes on that players version of the game the:
- game player prefab
- player prefab
but when players spawn in (after countdown and scene change)they all share the same prefab chosen by what I believe is the last player to join the lobby. It says they all have a different prefab before the scene loads but then they all share the same player prefab. The code works in the way that there can be more than 1 prefab but players cant chose a different one from each other…
(All players inherit the prefab of the host)
Any help would be nice !!!
THANKS IN ADVANCE

Hi! I just made a tutorial about this: https://forum.unity3d.com/threads/tutorial-character-selection-from-a-lobby.483535/

–

1 Answer

1

Hi, what does your lobby player script say? It looks like you’re always spawning the same “lobbyPlayerPrefab” at the host so are you somehow sending a CMD from your client to let the host know what to switch to?

Areleli

Sorry oops miss read what you said, So basically my solution: I made it spawn an empty prefab with a script on it that then replaces the player accordingly... you could add a UI to the empty and have a few replaceplayer functions etc

–