Search Unity

[Solved] How to leave and rejoin the Network Lobby Manager?

Discussion in 'Multiplayer' started by Doug_B, Nov 17, 2017.

  1. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    Firstly, please excuse my posting a question on the Forum. It seems there are presently some login problems to the Questions area that prevent me from using it.

    Scenario

    Using the Network Lobby Manager from the Asset Store, I would like to run through the following 4-scene 2-player game sequence, on both a Host and Client (using either Manual Connection or Matchmaking) :

    1. Enter Scene 0 as a non-Lobby with no Lobby Manager present.
    2. Change to Scene 1 which is the Network Lobby (Lobby Manager created at this point).
    3. Host presses "Play and Host"
    4. Client Presses "Join"
    5. Now in the LobbyPanel both Host and Client press Join.
    6. Change to Scene 2 which is the Network game.
    7. Change to Scene 3 which is post game outside of the Lobby Manager (i.e. Lobby Manager has been destroyed).
    8. Change back to Scene 0.
    9. Progress back through to Step 6 (i.e. to play the game again).

    The problem

    At Step 4 (2nd time round after Step 9), the Host process works as expected, which is to say, the same as it did the first time through the sequence.
    However, the Client joins the lobby then immediately errors with "A connection has already been set as ready. There can only be one."

    Here's some context ...

    Software Components
    1. Unity 2017.1.1f1 Personal
    2. Asset Store Network Lobby

    References Searched

    Here is a list of resources I have used trying to find a solution to my problem.

    Tutorials
    1. This was a handy series
    2. This was another informative video

    Unity Questions and Forums
    I have read a number of questions that are closely linked to the problem I am seeing. Here is just a taster :

    3. This question sees a similar error message that I am getting
    4. This question again sees a similar error message but is a self implemented solution
    5. This question seems to be the very same problem and says that there is a bug fix already reported. However that fix says it is in review as of 2015 (two years ago at the time of writing)​

    Example Solutions Attempted

    I have tried various solutions. For example, one was to try doing this on the Server in the Game scene :
    Code (csharp):
    1.  
    2.         foreach (var slot in lobbySlots)
    3.         {
    4.             if (slot)
    5.                 slot.readyToBegin = false;
    6.         }
    7.  
    My latest attempt has been to try this:

    1. At the end of the Game-scene, change the lobby to be the post-game-scene and switch the Server to that scene, like this:
    Code (csharp):
    1.  
    2.         [ServerCallback]
    3.         LobbyManager.s_Singleton.lobbyScene = "Post game";
    4.         LobbyManager.s_Singleton.ServerReturnToLobby();
    5.  
    2. The Post-game-scene (client and server side) has this code:
    Code (csharp):
    1.  
    2.         void Start ()
    3.         {
    4.             StartCoroutine(ChangeScene());
    5.         }
    6.  
    7.         IEnumerator ChangeScene()
    8.         {
    9.             var lobby = Object.FindObjectOfType<LobbyManager>();
    10.             float fTime = 3f;
    11.  
    12.             if(!NetworkServer.active)
    13.             {
    14.                 yield return new WaitForSeconds(fTime);
    15.                 Debug.Log("StopClient");
    16.                 LobbyManager.s_Singleton.StopClient();
    17.             }
    18.             else
    19.             {
    20.                 while (Network.connections.Length > 0)
    21.                     yield return null;
    22.  
    23.                 Debug.Log("StopHost");
    24.                 LobbyManager.s_Singleton.StopHost();
    25.             }
    26.  
    27.             yield return new WaitForSeconds(fTime);
    28.             Debug.Log("Shutdown");
    29.             NetworkManager.Shutdown();
    30.  
    31.             yield return new WaitForSeconds(fTime);
    32.             Debug.Log("Destroy");
    33.             DestroyObject(lobby.gameObject);
    34.     //        Destroy(NetworkManager.singleton.gameObject);
    35.         }
    36.  
    Statement of the Question

    From the tutorial links posted above and also from using the Asset Store Network Meteoroid project, it appears that all solutions using the Network Lobby Manager rely on having only 2 scenes, to wit: the lobby and the game. The code simply switches to and fro between these 2 scenes.

    How then, for each of a Server, Host and Client, can the LobbyManager be properly closed down to allow changing to other scenes and then back to a new Network Lobby game? Or must I write an entire lobby manager from scratch to handle this?

    Thanks for any assistance with this. :)
     
  2. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    For anyone interested, here is my solution: move to using Photon.
    I have found it simpler to use than UNet and, so far, with fewer problems / bugs.
    About the only issue has been that prefabs must be placed under a Resources folder rather than being directly registered as with the Unity solution.
    However, below is a script to get round that problem. Here is a suggested way to use it:
    1. Make a prefab marked as DoNotDestroyOnLoad.
    2. Add script below to it.
    3. In the Editor, set the array size to however many prefab GameObjects you have.
    4. Drag your prefabs into the array slots.
    5. In scripts, create [SerialiseField] entries and in the Editor drop in your GameObject prefabs as you would normally.
    6. When instantiating a prefab in Photon, just call GetPath() in the script below handing in your GameObject reference and you will get back the path to the resource file.
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3.  
    4. [ExecuteInEditMode]
    5. public class MgrResourcePrefabs : MonoBehaviour
    6. {
    7.     #region Set in Editor
    8.     [System.Serializable]
    9.     public class CPrefab
    10.     {
    11.         public GameObject prefab;
    12.         public string sPath;
    13.     }
    14.  
    15. #pragma warning disable 649
    16.     [SerializeField] List<CPrefab> listPrefabs = new List<CPrefab>();
    17. #pragma warning restore 649
    18.     #endregion
    19.  
    20.     #region Public
    21.     public string GetPath(GameObject go)
    22.     {
    23.         return listPrefabs[listPrefabs.FindIndex(x => x.prefab == go)].sPath;
    24.     }
    25.     #endregion
    26.  
    27.     #region Unity Editor only
    28. #if UNITY_EDITOR
    29.     void Update()
    30.     {
    31.         foreach (var go in listPrefabs)
    32.         {
    33.             go.sPath = FormatPath(go.prefab);
    34.         }
    35.     }
    36.  
    37.     string FormatPath(GameObject go)
    38.     {   // Extract path text between "...Resources/" and ".prefab"
    39.         var s = UnityEditor.AssetDatabase.GetAssetPath(go);
    40.         var pos = s.IndexOf(ksResources) + ksResources.Length + 1;
    41.         return s.Substring(pos, s.Length - pos - 7);
    42.     }
    43.  
    44.     const string ksResources = "Resources";
    45. #endif
    46.     #endregion
    47. }
    48.