Issues with Relay creation after playing a match

Hi,

I am currently working on chess-like 1v1 game, and I am having bug that I am unable to solve. For networking I am using Relay, and on the high level the networking looks something like that:
Joining player inputs code, when host detects 2 data transmitters, it sends to the other client important data, and then they both communicate using RPC(the data that is sent in the beginning is too sent using this way). And when the player quits the game, i tam using simply this line to disconnect:

if (NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsClient)
{ 
    NetworkManager.Singleton.Shutdown();
}

But after disconnecting this way, when host tries to host another game i get this error:

NullReferenceException: Object reference not set to an instance of an object
Unity.Netcode.NetworkBehaviour.__endSendClientRpc (Unity.Netcode.FastBufferWriter& bufferWriter, System.UInt32 rpcMethodId, Unity.Netcode.ClientRpcParams clientRpcParams, Unity.Netcode.RpcDelivery rpcDelivery) (at ./Library/PackageCache/com.unity.netcode.gameobjects@1.7.1/Runtime/Core/NetworkBehaviour.cs:210)
DataTransmitter.SendColorToClientRpc (System.Boolean color) (at Assets/Scripts/Networking/DataTransmitter.cs:165)
DataTransmitter.SendColor () (at Assets/Scripts/Networking/DataTransmitter.cs:156)
HostCanvas.SetColors () (at Assets/Scripts/Canvases/HostCanvas.cs:134)
HostCanvas.OnEnable () (at Assets/Scripts/Canvases/HostCanvas.cs:69)
System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__7_0 (System.Object state) (at <17d9ce77f27a4bd2afb5ba32c9bea976>:0)
UnityEngine.UnitySynchronizationContext+WorkRequest.Invoke () (at <f7237cf7abef49bfbb552d7eb076e422>:0)
UnityEngine.UnitySynchronizationContext.Exec () (at <f7237cf7abef49bfbb552d7eb076e422>:0)
UnityEngine.UnitySynchronizationContext.ExecuteTasks () (at <f7237cf7abef49bfbb552d7eb076e422>:0)

this error occures here, and it occurs only on the host side, and client never gets the message:

    public void SendColor(){
        if (NetworkManager == null) {
            Debug.LogError("NetworkManager.Singleton is null!1");
            return;
        }
        if(NetworkManager.Singleton.IsHost){
            SendColorToClientRpc(!gameManager.color);
        }
    }

    [ClientRpc]
    private void SendColorToClientRpc(bool color){

        Debug.Log("RECEIVING COLORRRRRRRRRRRRRR"); // The error is in this line
        
        if (!NetworkManager.Singleton.IsHost) {
            gameManager.SetColor(color);
        }
    }

I am not sure if it helps, but two observations that I made are that:

  1. When the user who was prieviously joining one, hosted game, everything would work correctly, but after dissconnecting again, it would start being totally unpredictable and sometimes it would work sometimes it wouldn’t
  2. Every time when I am trying to leave a match, and host another one, the client iD for host is always 0, and for the client it is always 1 more than before, if connection was cut, shouldn’t it be always this always be 0 and 1?

I have already seen this post Issue with Lobby - Unable to Create New Lobby After Playing a Match but I don’t use anywhere events in networking, so it didn’t help me in any way.

I would appreciate any insights or suggestions on how to resolve this issue. If you need any additional information or code snippets, please let me know, and I’ll be happy to provide them.

Thank you in advance
Mawerty

Is the NetworkManager in a scene that gets loaded again? If so, it gets duplicated. Make sure it’s in a launch scene of some kind that never gets loaded again. Do not use the Destroy(NetworkManager.Singleton) approach as many, many tutorials have it.

Other than that, check your networking lifecycle flow. And any singletons. There’s a reason why I visualized this with a Statemachine.

A common issue is starting to host again immediately. You have to wait for the shutdown to complete. Though if this requires user interaction the host would have to to so within a very short time period (within the range of RTT or several).

The way you describe the issue it seems like the host isn’t actually ending the session, otherwise the clientId wouldn’t be incrementing. Make sure that the host is in fact calling shutdown and does so on the one and only instance of NetworkManager, not a duplicate.

What’s the point of this conditional? It will only not be true for a dedicated server which I assume you don’t have in a 1v1 game with Relay.

You may have other such conditionals in your code that aren’t thought through. Those may lead to issues too. Be sure to familiarize yourself with the Server, Host, Client, Owner concepts and perhaps log them for individual clients or objects to know what they are, so you aren’t making unnecessary (complex) conditionals or ones that are mutually exclusive.

Hey,
My game is small enough that I have my entire game on one scene, so this isn’t the case, and I don’t see any other way in which I could accidently duplicate the NetworkManager in my code. When it comes to the timing, the hosting again is being always done over second after Shutdown, so this isn’t the case too.

And the host is calling shutdown, and it disconnects other player, and when it is hosting second time, I can see that it sees itself, and the new client, so I assume that it works.

When it comes to the lifecycle flow, my game entire networking code is CreateRelay, and JoinRelay, that are copied from internet, a 10 RPC functions and thats all. And what I currently want my code to do is to somehow destroy current session and call again CreateRelay.

I know that it is wrong to do it this way, but for now I want to have simpliest possible solution that allows me to have playable game, and later when I have entire game somehow working I want to rewrite it in a clever way.

Is there anything obvious that I am missing, or some clever solution to my problem?

Not sure which NGO version you use but we now have the [Rpc] attribute. Use that to change your ClientRpc to be received by only clients with SendTo.NotServer. This makes RPCs more specific since you seem to have that issue because the Host calls the ClientRpc on itself (host is also a client).

Perhaps you call SendColor in Update? If so, you need to be careful since if you call Shutdown then ShutdownInProgress may be true at which point you mustn’t send any RPCs anymore. I’m guessing this may be a timing issue where you still send RPCs after Shutdown was called.