Search Unity

  1. Unity 2019.1 is now released.
    Dismiss Notice
  2. We've opened up a space to discuss, share feedback, and showcase everything related to the Unity Shader Graph! Come show us what you've made.
    Dismiss Notice

Unity Multiplayer SpawnWithClientAuthority NetworkConnection is not ready

Discussion in 'Connected Games' started by paulsohops, Mar 28, 2018.

  1. paulsohops

    paulsohops

    Joined:
    Apr 16, 2014
    Posts:
    2
    I am trying out the Network Lobby asset (https://assetstore.unity.com/packages/essentials/network-lobby-41836) and running into an issue with SpawnWithClientAuthority. My linked player prefab has the following code:

    Code (CSharp):
    1. public GameObject Piece;
    2.  
    3. public override void OnStartLocalPlayer() {
    4.     CmdSpawnPiece();
    5. }
    6.  
    7. [Command]
    8. void CmdSpawnPiece()
    9. {
    10.     GameObject piece = Instantiate(Piece);
    11.     NetworkServer.SpawnWithClientAuthority(piece, connectionToClient);
    12. }
    But, once two players have joined a game through the lobby (with one acting as host), I get the following error on the hosting player:

    "SpawnWithClientAuthority NetworkConnection is not ready! UnityEngine.Networking.NetworkServer:SpawnWithClientAuthority(GameObject, NetworkConnection)"

    It worked fine before I was using the NetworkLobbyManager, with just the basic NetworkManager and NetworkMangerHud. What seems to be happening is when the scene is changes from the lobby scene to the main scene, the hosting player's connection is not set to ready (through ClientScene.Ready() or something) before OnStartLocalPlayer is called.

    Is there a function I can override in my player prefab NetworkBehavior class that will get called after the connection is set to ready, or is there an alternative way to spawn objects for players after they join? Thanks for the help!
     
  2. paulsohops

    paulsohops

    Joined:
    Apr 16, 2014
    Posts:
    2
    I did some digging around and think the right way to go about this is something like this:
    Code (CSharp):
    1. [Command]
    2. void CmdSpawnPiece()
    3. {
    4.     if (connectionToClient.isReady) {
    5.         GameObject piece = Instantiate(Piece);
    6.         NetworkServer.SpawnWithClientAuthority(piece, connectionToClient);
    7.     } else {
    8.         connectionToClient.RegisterHandler(MsgType.Ready, OnReady);
    9.     }
    10. }
    11.  
    12. void OnReady(NetworkMessageDelegate msg)
    13. {
    14.     GameObject piece = Instantiate(Piece);
    15.     NetworkServer.SpawnWithClientAuthority(piece, connectionToClient);
    16. }
    However, there seems to be an issue with this approach because of the engine code here: https://bitbucket.org/Unity-Technol...leviewer=file-view-default#ClientScene.cs-299

    In ClientScene.Ready, there is this code:
    Code (CSharp):
    1. var msg = new ReadyMessage();
    2. conn.Send(MsgType.Ready, msg);
    3. s_IsReady = true;
    4. s_ReadyConnection = conn;
    5. s_ReadyConnection.isReady = true;
    6. return true;
    It looks like the Ready message is being sent to the connection before isReady is set to true. So in my code snippet above, I would catch the message with OnReady, try to do SpawnWithClientAuthority, and get an error because the connection's isReady is still false.

    I've put in a workaround for now where I'm firing a custom message from my NetworkLobbyManager.OnLobbyClientSceneChanged (which is called after the NetworkManager's base
    OnClientSceneChanged is called and the connection is set to ready), and that's the message I'm registering against to spawn my stuff.
     
    Nigey likes this.
  3. Nigey

    Nigey

    Joined:
    Sep 29, 2013
    Posts:
    1,109
    Is this work around still okay for you? It's happening to me too. I'm pretty surprised there such a basic bug in their source code.
     
  4. thedrhax14

    thedrhax14

    Joined:
    Aug 7, 2014
    Posts:
    23
    I managed to use IEnumerator to workaround it. Here is my code:
    Code (CSharp):
    1. void Start() {
    2.     Debug.Log("[OnlinePlayer] Started");
    3.     CmdSpawnController();
    4. }
    5.  
    6. [Command]
    7. public void CmdSpawnController() {
    8.     Debug.Log("[OnlinePlayer] Spawning " + Team + " controller");
    9.     if (connectionToClient.isReady) {
    10.         Spawn();
    11.     } else {
    12.         StartCoroutine(WaitForReady());
    13.     }
    14. }
    15.  
    16. IEnumerator WaitForReady() {
    17.     while (!connectionToClient.isReady) {
    18.         yield return new WaitForSeconds(0.25f);
    19.     }
    20.     Spawn();
    21. }
    22.  
    23. [Server]
    24. void Spawn() {
    25.     GameObject controller = Instantiate(chosenController);
    26.     NetworkServer.SpawnWithClientAuthority(controller, connectionToClient);
    27. }
    This code is on my game player object, which is set in my network manager.
     
    Nigey likes this.
  5. Kirchesch

    Kirchesch

    Joined:
    Oct 17, 2017
    Posts:
    2
    What this [Server] do? why not re-calling CmdSpawnController()?
     
  6. thedrhax14

    thedrhax14

    Joined:
    Aug 7, 2014
    Posts:
    23
    Because clients can not instantiate in the network, but server can. So, if client wan't to spawn something, it should ask server to do so, assign the client and give the authority. Also, by the time server waits, it doesn't need to double check the ready status of the client. Moreover, commands methods are only called from client on server. Server can't run commands. There is an alternative way of doing this, but this seems reliable.

    [Server] attribute doesn't allow client instance to call the followed method. I usually use it when it comes to spawning things. Btw, "spawn" is not always "instantiate". It can be also "move existing one to spawn point and set authority".

    Code breakdown is below:
    1. The code runs on client side
    2. OnStart it asks server to spawn the controller, but the client may still be loading even if the game code have already started working. Because of this, client is set as not-ready.
    3. Server sees it and waits in the IEnumerator in while loop.
    4. While loop breaks once client is ready.
    5. Server (only) spawns controller and gives the client authority.
    [/QUOTE]
     
    Kirchesch likes this.