Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Relay - What does NetworkStateMismatch mean?

Discussion in 'Multiplayer' started by BlueTanda, Oct 10, 2022.

  1. BlueTanda

    BlueTanda

    Joined:
    Oct 28, 2017
    Posts:
    5
    When attempting to connect a client to my Relay host, I get the status code error:
    Networking.Transport.Error.StatusCode.NetworkStateMismatch

    The human readable translation is:
    "Sending data while connecting on connection {0} is not allowed.";

    What are the possible causes of this error? I get this error even when running the instance on separate machines - one is my Smartphone with WiFi disconnected, so I've ruled out bottlenecks on the same router.
     
  2. simon-lemay-unity

    simon-lemay-unity

    Unity Technologies

    Joined:
    Jul 19, 2021
    Posts:
    184
    The most common cause for this error is attempting to send data on a connection that is not in the connected state (either because it's in the process of being established, or because it has been disconnected).

    Are you using Netcode for GameObjects? If so, which version?
     
  3. BlueTanda

    BlueTanda

    Joined:
    Oct 28, 2017
    Posts:
    5
    I'm using version 1.0.2

    The join code is:
    private async Task JoinEvent(string q_string)
    {
    RelayManager.RelayJoinData joinData;

    joinData = await RelayManager.JoinGame(q_string);
    eventCodeText.text = "Success";
    codeInputObject.SetActive(false);

    //Retrieve the Unity transport used by the NetworkManager
    UnityTransport transport = NetworkManager.Singleton.gameObject.GetComponent<UnityTransport>();

    // Establish the allocation data to use Relay
    transport.SetClientRelayData(joinData.IPv4Address, joinData.Port, joinData.AllocationIDBytes, joinData.Key, joinData.ConnectionData, joinData.HostConnectionData);

    // Start this instance as the Host
    bool worked = false;
    worked = networkManager.StartClient();
    if (worked)
    eventCodeText.text = "Client established";
    else
    eventCodeText.text = "Client did not establish";
    }

    (eventCodeText is a local TextMeshPro used for real-time display without having to look at the Debug.Log results) - The "Client established" confirmation displays, but NetworkManager.ConnectedClientsList.Count doesn't change and the error occurs when trying to use a ServerRpc.
     
  4. simon-lemay-unity

    simon-lemay-unity

    Unity Technologies

    Joined:
    Jul 19, 2021
    Posts:
    184
    Ah I see. I think there might be a misunderstanding about what
    StartClient
    does. If it returns successfully, it only means that the connection process has been successfully started. It doesn't mean that the connection has been fully established yet (I know, it's a bit counter-intuitive).

    If you want to know when the connection is ready, you can register a
    OnClientConnectedCallback
    on the
    NetworkManager
    . This will let you know when the connection has been fully established. Only after this callback is invoked is it safe to send RPCs and other messages.
     
  5. BlueTanda

    BlueTanda

    Joined:
    Oct 28, 2017
    Posts:
    5
    That makes sense, but it's revealed a different problem - the host code seems to become invalid after a short time. If I enter the code quickly and try to connect a client, the StartClient returns true but then gets no further. If I wait somewhere between 8-10 seconds, StartClient returns false. I need to figure out if there's something else I need to do to keep the connection by the host active.

    This is all the host connection code. I assumed that binding happened behind the curtain, but is there something else I need here?

    private async Task LaunchHost()
    {
    RelayManager.RelayHostData hostData;

    hostData = await RelayManager.HostGame(4);
    eventCodeText.text = "Code: " + RelayManager.hostCode;

    roomManager.PopulateRosters();

    //Retrieve the Unity transport used by the NetworkManager
    UnityTransport transport = NetworkManager.Singleton.gameObject.GetComponent<UnityTransport>();

    // Establish the allocation data to use Relay
    transport.SetHostRelayData(hostData.IPv4Address, hostData.Port, hostData.AllocationIDBytes, hostData.Key, hostData.ConnectionData);

    // Start this instance as the Host
    networkManager.StartHost();

    }
     
  6. simon-lemay-unity

    simon-lemay-unity

    Unity Technologies

    Joined:
    Jul 19, 2021
    Posts:
    184
    Once the host is started it should keep the connection alive on its own (as long as the network manager keeps being updated). Have you checked that
    StartHost
    succeeds?
     
  7. BlueTanda

    BlueTanda

    Joined:
    Oct 28, 2017
    Posts:
    5
    Yes, I'm getting a 6-character join code and the return value is true, confirmed by:

    // Start this instance as the Host
    bool worked = false;
    worked = networkManager.StartHost();
    if (worked)
    eventCodeText.text += "\nConnected";
    else
    eventCodeText.text += "\nFailed";
     
  8. simon-lemay-unity

    simon-lemay-unity

    Unity Technologies

    Joined:
    Jul 19, 2021
    Posts:
    184
    What is the value of the "Hearbeat Timeout Ms" setting under the "Unity Transport" component?

    Also, have you checked that the
    isSecure
    parameter of
    SetClientRelayData
    and
    SetHostRelayData
    matches that of the endpoint you selected from the Relay allocation? For example, if you select the endpoint with connection type "dtls", you should set the
    isSecure
    parameter to true.
     
  9. BlueTanda

    BlueTanda

    Joined:
    Oct 28, 2017
    Posts:
    5
    Brilliant - setting isSecure to true solved the problems! SetClientRelayData and SetHostRelayData were defaulting to a false value for isSecure. Forcing to true worked.

    For reference, Heartbeat Timeout MS is unchanged from the default 500.

    Thanks