Search Unity

[Solved] Trouble with ClientScene.ConnectLocalServer()

Discussion in 'Multiplayer' started by Iron-Warrior, Aug 12, 2015.

  1. Iron-Warrior

    Iron-Warrior

    Joined:
    Nov 3, 2009
    Posts:
    838
    Hi, I'm trying to build my own NetworkManager, and to do this I've been looking at the source through ILSpy, but I've been having trouble with ClientScene.ConnectLocalServer() and I can't find many resources on it.

    As far as I can tell, on calling this method the client will connect locally to the server, making this user the host. By doing this I should be able to treat the local client exactly like a remote client. I'm having a few issues setting this up.

    Here is the current network manager I am using.

    Code (csharp):
    1. using UnityEngine;
    2. using UnityEngine.Networking;
    3. using System.Collections;
    4.  
    5. public class NetworkingManager : MonoBehaviour {
    6.  
    7.     [SerializeField]
    8.     GameObject playerPrefab;
    9.  
    10.     public string host { get; set; }
    11.     public string playerName { get; set; }
    12.  
    13.     private NetworkClient client;
    14.  
    15.     void Awake () {
    16.         host = "localhost";
    17.         playerName = "Iron Warrior";
    18.  
    19.         DontDestroyOnLoad(gameObject);
    20.     }
    21.  
    22.     public void Host()
    23.     {
    24.         Debug.Log("Hosting game...");
    25.  
    26.         NetworkServer.Listen(7777);
    27.         NetworkServer.RegisterHandler(MsgType.Connect, OnServerConnect);
    28.  
    29.         Application.LoadLevel(1);
    30.  
    31.         ClientScene.RegisterPrefab(playerPrefab);
    32.  
    33.         client = ClientScene.ConnectLocalServer();
    34.         client.connection.isReady = true;
    35.     }
    36.  
    37.     public void Join()
    38.     {
    39.         Debug.Log("Joining game...");
    40.  
    41.         ClientScene.RegisterPrefab(playerPrefab);
    42.  
    43.         client = new NetworkClient();
    44.         client.Connect(host, 7777);
    45.  
    46.         Application.LoadLevel(1);
    47.     }
    48.  
    49.     void OnServerConnect(NetworkMessage netMsg)
    50.     {
    51.         Debug.Log("Client has connected");
    52.  
    53.         NetworkServer.SetClientReady(netMsg.conn);
    54.  
    55.         GameObject player = SpawnPlayer();
    56.         NetworkServer.Spawn(player);
    57.     }
    58.  
    59.     GameObject SpawnPlayer()
    60.     {
    61.         Vector3 spawnPoint = GameObject.FindObjectOfType<SpawnHandler>().GetRoundRobinSpawnPoint();
    62.         GameObject player = (GameObject)Instantiate(playerPrefab, spawnPoint, Quaternion.identity);
    63.  
    64.         return player;
    65.     }
    66. }
    67.  
    To test if everything works I have a short script attached to the playerPrefab GameObject:

    Code (csharp):
    1. using UnityEngine;
    2. using UnityEngine.Networking;
    3. using System.Collections;
    4.  
    5. public class TestingRPCs : NetworkBehaviour
    6. {
    7.     public void Start()
    8.     {
    9.         if (isServer)
    10.             RpcTest();
    11.     }
    12.  
    13.     [ClientRpc]
    14.     void RpcTest()
    15.     {
    16.         Debug.Log("RPC call done");
    17.         GetComponent<Renderer>().material.color = Color.red;
    18.     }
    19. }
    What I thought should happen would be that the local client would connect, triggering the OnClientConnect message, which would spawn a player across the network, which would then trigger the RpcTest method. Unfortunately the OnClientConnect does not get called. I've tried bypassing that method and just spawning a player directly in the Host() method, but the Rpc is not called, so it doesn't seem to be aware of the local client.

    How are the local clients supposed to be setup? I can't find any examples in the documentation, so I'm not sure what I'm doing wrong.

    Thanks for any help,
    Erik
     
    Last edited: Aug 12, 2015
  2. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    is "isServer" true in Start()? I'd suggest using OnStartServer() instead, where the server state is guaranteed to be setup.

    Just a note on naming conventions, your function "OnClientConnect" is called on the server. The UNet code in general uses a naming scheme where the place that the function is called is the first part of the function name. So "OnServerConnect" is called on the server, and "OnClientConnect" is called on the client.
     
  3. Iron-Warrior

    Iron-Warrior

    Joined:
    Nov 3, 2009
    Posts:
    838
    Hey Seanr, thanks for the reply. I've updated my above code to reflect the proper naming conventions.

    "isServer" is true in Start, and the call works (to the remote client, but not the host) when I build and connect using the Join() method. Is the MsgType.Connect supposed to be sent when a client is connected by ClientScene.ConnectLocalServer()? When I connect with a remote client the method is run, but ConnectLocalServer does not call it. To ensure that ConnectLocalServer is working properly I debugged out NetworkServer.active right after making the ConnectLocalServer(), and it returns true.

    EDIT: I also added client.connection.isReady = true; to ensure that the local connection is set to ready.

    EDIT2: Running in the Editor with the network info tab I can see that IsClient and IsServer are both set true, as well as HasAuthority. Getting closer...

    EDIT3: I registered a handler with the local client using NetworkClient.RegisterHandler, and then sent messages from the server to all clients, which were properly received. The plot thickens. Do I need to register the local client to be able to receive RPC calls for any reason?

    EDIT4: Solved! I tried to send messages only to the ready clients, which didn't work. This made me realize that the server likely didn't recognize the client as ready, despite that I was setting it in the initial setup. I instead moved the ready activation into the delegate for the MsgType.Connect, like so.

    Code (csharp):
    1. void OnClientConnect(NetworkMessage netMsg)
    2.     {
    3.         Debug.Log("Client has connected");
    4.  
    5.         ClientScene.Ready(netMsg.conn);
    6.     }
    7.  
    8. ...
    9.  
    10.     void StartHost()
    11.     {
    12.  
    13.         client = ClientScene.ConnectLocalServer();
    14.         client.RegisterHandler(MsgType.Connect, OnClientConnect);
    15.         ClientScene.RegisterPrefab(playerPrefab);
    16.  
    17.         NetworkServer.SpawnObjects();
    18.  
    19.         GameObject player = SpawnPlayer();
    20.         NetworkServer.Spawn(player);
    21.     }
    22.  
    And now the RPC calls work! I feel dumb now though...seems obvious in retrospect. Hopefully this topic will be useful to people searching.
     
    Last edited: Aug 13, 2015