Search Unity

Resolved How should I Send a Player Disconnected Message to Remaining Connected Clients?

Discussion in 'Netcode for GameObjects' started by Ghujelk, May 27, 2021.

  1. Ghujelk

    Ghujelk

    Joined:
    May 21, 2015
    Posts:
    15
    When a connected client calls StopClient, I see in the console of my host player a "[MLAPI] Disconnect Event From... " message.

    My intention was to listen for that event on the server/host, and then broadcast that message via RPC to the remaining connected clients, along with the disconnecting player ID so remaining connected players can clean up various UI and objects related to the now disconnected player.

    However, when I try
    NetworkManager.Singleton.OnClientDisconnectCallback += PlayerDisconnectClientRpc,

    I start the server/host, and connect Client A and Client B, then when Client B disconnects,
    After the Disconnect Event I get a NullReferenceException: Could not get NetworkObject for the NetworkBehaviour. Are you missing a NetworkObject component? error on the server/host,

    Client A console shows a Trying to destroy object [client B ID] but it doesn't seem to exist anymore! warning,

    The script is attached to the same gameObject with the MLAPI NetworkManager component (it's actually the HelloWorldManager from the MLAPI example), And the only logic in the Rpc method is a Debug.Log("Player DC"); statement for testing.

    Am I approaching this correctly, and just implementing the messages incorrectly? Or should I be looking at some other synced variable or event to have the server let other players know when and who disconnects?
     
  2. Ghujelk

    Ghujelk

    Joined:
    May 21, 2015
    Posts:
    15
    After further testing I believe I resolved this, the main issue seems to be that the script component where I was calling the ClientRpc from did not have an MLAPI NetworkObject component attached to it. It did have the MLAPI NetworkManager attached to it, which doesn't allow you to also have a NetworkObject component attached at the same time.

    To resolve all of this, I moved the script component that was sending the ClientRpc to a different object in the scene, and attached a MLAPI Network Object component to it. Now, whenever any non host client disconnects, all other players are notified via Rpc which client disconnected.
     
  3. mitio31

    mitio31

    Joined:
    Apr 17, 2020
    Posts:
    3
    Hey! I have recently got into the same problem and here is something that I think will be useful for you.

    First of all, there is a difference between NetworkObjectId and the clientId that is passed in the OnClientDisconnectCallback function. That's because MLAPI gives player objects NetworkObjectId, which can be assigned to network objects aswell (NPCs, mobs, etc.) and clientId, which is unique ID ONLY for players. For example if you have multiple network objects in your game, if you try the following:
    Code (CSharp):
    1. Debug.Log(NetworkObjectId)
    and
    Code (CSharp):
    1. Debug.Log(NetworkManager.Singleton.LocalClientId)
    the output will most likely be different, because in the first case you get the unique network object id, and in the second case you get the unique PLAYER ONLY id.

    I think your get that null exception, because you try to take the networkObjectId of the disconnected client, which is no longer there. The only thing you have access to is the clientId, that is passed in the callback function.

    The second thing I could advice you, the NetworkManager callbacks are invoked ONLY on the server. I do not advice you to assign ClientRpc to the callback function. Better create a function (it will be executed on the server), and from this function call ClientRpc in order to tell the clients that the player with "clientId" has disconnected and then you can do whatever you want with it.

    I hope I explained it as good as I can.
     
    edmartine418 likes this.
  4. Ghujelk

    Ghujelk

    Joined:
    May 21, 2015
    Posts:
    15
    Thanks for the input! I did find that there is a difference between the networkObjectId and the clientId when joining and removing connected players and spawning objects on the server, in my test case though I wasn't using either Id in any logic, only a Debug.Log statement here and there. But the console error really led me to believe that MLAPI needs a network object component on anything that also wants to use Rpc's, and I guess by design you can't have an object with both the NetworkManager and the NetworkObject components simulateously.

    I'll use your suggestion about subscribing a non-Rpc method to the callback though, that seems like a better way to do what I'm aiming for!
     
  5. luke-unity

    luke-unity

    Joined:
    Sep 30, 2020
    Posts:
    306
    You are right any script which wants to use RPCs must be on a GameObject with a NetworkObject component. In addition you can only put RPC functions on scripts deriving from NetworkBehaviour and not on regular MonoBehaviours.
     
  6. Ghujelk

    Ghujelk

    Joined:
    May 21, 2015
    Posts:
    15
    Thank you for the verification @luke-unity! Double checking the documentation I see it is also expressed clearly on the NetworkObject page, however the various RPC related pages do not explicitly mention that requirement. If I could make a suggestion, it would be to request whoever adds to the documentation to include this fundamental information on those pages as well!