Search Unity

I forgot how to detect player / client / server disconnection. Anyone can tell me?

Discussion in 'Multiplayer' started by asperatology, Oct 1, 2015.

  1. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    981
    I must be glossing over something important. In NetworkBehaviour, I see that there are two event methods I can use for detecting disconnection: OnDisconnectFromServer() and OnPlayerDisconnected().

    When a network game starts and the client connects to the server, I added the NetworkBehaviour script component containing OnDisconnectFromServer() and OnPlayerDisconnected(). When the client disconnects from the server, however, both the OnDisconnectedFromServer() and OnPlayerDisconnected() event methods did not fire at all.

    At the bottom of this Manual article, I found the closest event method related to player/client/server connection and disconnection. But even that event doesn't fire.

    It must be telling me I cannot add new script components at runtime and expect the new script components to call on OnDisconnectFromServer() or OnPlayerDisconnected() methods when the client disconnects from server.

    What should I do? What details am I forgetting?


    EDIT:

    In fact, I don't even know what Network Manager is doing when it is stopping the connection to disconnect the client from the server. Why is OnPlayerDisconnected() or OnDisconnectedFromServer() not called when connection is stopped for client and server? No Log messages or anything.

    EDIT 2:

    NetworkManager calls on Destroy() for game objects spawned in with NetworkServer.Spawn() or NetworkServer.SpawnWithClientAuthority(). The game objects with NetworkBehaviours or MonoBehaviours attached will not get a chance to run OnDisconnectFromServer(), OnPlayerDisconnected(), or any On...() event methods. Go for OnDestroy() when using NetworkManager to handle/destroy game objects.

    Still, it would be nice to know how to trigger OnDisconnectFromServer() and OnPlayerDisconnected() if the client disconnects from server in UNET. Thread is still relevant and open.
     
    Last edited: Oct 1, 2015
  2. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    those functions (OnDisconnectFromServer,OnPlayerDisconnected,etc) are from the legacy networking API, not UNet.
     
  3. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    981
    Ah. Back to the dreadful docs again.

    So, what event methods are triggered that UNET uses?

    If they don't use event methods, what class object does UNET handle server/client/player disconnection?
     
  4. l3fty

    l3fty

    Joined:
    Mar 23, 2013
    Posts:
    87
  5. joeri_07

    joeri_07

    Joined:
    Dec 18, 2015
    Posts:
    45
  6. Leoo

    Leoo

    Joined:
    May 13, 2013
    Posts:
    96

    We all want to be able to do that, but sadly guys at unity think that type of feature is not needed on the HLPI.. Lol?
    You have to build your own "PlayerManager" to be able to do stuff like that, UNET is player "object" oriented, not player "connection" oriented it seems like.

    http://forum.unity3d.com/threads/player-manager.350351/
     
    dogramacigokhan likes this.
  7. l3fty

    l3fty

    Joined:
    Mar 23, 2013
    Posts:
    87
    In my system, once a player connects and has authorized/validated I store their particulars in a custom player class. Within that is a field for their current connection id, so I can perform a lookup (though that connection id can belong to someone else at a different time in the game session after connections & disconnections, so additional validation can be required).

    Unity is holding a lot of data about the client in that network connection object too though, including a list of clientOwnedObjects which might give you a shortcut to get their player object on your server.

    https://docs.unity3d.com/ScriptReference/Networking.NetworkConnection.html
    https://docs.unity3d.com/ScriptReference/Networking.NetworkConnection-clientOwnedObjects.html

    Hope this helps :)
     
  8. joeri_07

    joeri_07

    Joined:
    Dec 18, 2015
    Posts:
    45
    conn.playerControllers[0].gameObject seemed to do the trick...

    i'm doing Destroy(conn.playerControllers[0].gameObject) in that method.
    Can anybody confirm this is the correct way to do this?

    thnx
     
  9. Max_Bol

    Max_Bol

    Joined:
    May 12, 2014
    Posts:
    168
    The easiest way to manage something like a Call whenever a player is connected or not is actually a tad bit simple when you do get how Unity Unet works... but only when you get it.

    Detecting when a player join or disconnect can be done like this :

    1) First, as you're obviously making an Online game, you mostly must have a NetworkManager component on some gameobject that doesn't get destroyed on load. If it hasn't already been done, you should create your own custom version of it. It's surely the most easy thing ever : Create a new script. Name it whatever you want (such as "NetworkManagerCustom" for the sake of explaination). Add "using UnityEngine.Networking;" and change MonoBehaviour to NetworkManager. I suggest you do it first as this and not just remove the original NetworkManager so you can easily access and put back the references within the "new" custom NetworkManager. (It's easily so that you don't forget or change a value or reference unwillingly.) Once the NetworkManagerCustom is exactly like your NetworkManager, you'll be able to remove the NetworkManager component as you custom script will now inherit is parameters.

    2) Now, you have pretty much access to every kind of original functions that were prior to the Unet implementation, but they are slightly different in how they requires you to use them. I suggest you take a look at the Official NetworkManager docs and check every public functions.

    3) Now, you're able to use a function like this in the Custom NetworkManager script you added :
    Code (CSharp):
    1.     public override void OnServerConnect(NetworkConnection Conn){ //Being called when a new client connect onto the host or server)
    2. }
    In the example above, OnServerConnect will only be called on the Host client/server so you got to implement your own way of allowing the Custom NetworkManager script to communicate with whatever other manager (like a UI manager) script you might need it to update. There's many way of doing it and how to do it will depend on what should be happening when a new player connect and what kind of information you might want from it.

    Note that, for the host (if you have an host), OnServerConnect will be called in the Awake() so if you wish to refer to some instances through that, you might have to do a small work-around by adding if(Conn.hostId>=0){} condition.

    This an example I'm currently using :

    Code (CSharp):
    1.     public override void OnServerConnect(NetworkConnection Conn){
    2.         if(Conn.hostId >= 0){
    3.         Debug.Log("New Client Connected");
    4.             SM_Manager.Instance.UpdateMatchNameString();
    5.         }
    6.     }
    For me, it's set in a way that the Host can change the game name and the connected client have it updated both when they connect and when it's changed while they are connected. While the modification of the String works if the sting is modified after the clients are connected, the initial state of the string is not updated when the client connect and is left empty. By adding that code above to my Custom NetworkManager script, as soon as the a new client is connected, the UI text string of that player (and, for the sake of safety, all the other clients connected) is updated with the right information. In my case, I'm building my game with my own lobby system which involve an customization menu and a bunch of different cameras that takes a % of the screen and all. It's a really complex multi-layered overlay + camera based UI system which is more or less self managed as the host has some available button and field that are displayed as Text component for connected clients or simply inactive/invisible.

    The Conn.hostID >= 0 is kind of a special trick that allows you to have a simple condition for the host.
    For the host, NetworkConnection.hostID is always equals to -1 because he's connected to its own server within the application itself (which doesn't requires a remote access) while for all the connected clients, NetworkConnection.hostID should return 0 because 0 equals the server. This is why you have to watch out if you're doing something by comparing the ID from the host or from a client perspective as both will return different ID values.

    For something like printing a text into a chat window, you could simply implement a system that allow the server to add its own set of string onto the chat window through a ChatManager script and then call it whenever required.

    Something like :

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Networking;
    3.  
    4. public class NetworkManagerCustom : NetworkManager {
    5.  
    6.     //When a new client connect to the Host server.
    7.     public override void OnServerConnect(NetworkConnection Conn){
    8.         if(Conn.hostId >= 0 && Chat_Manager.Instance != null){
    9.             Chat_Manager.Instance.ServerChatMsg("New Player has joined");
    10.         }
    11.     }
    12. }
    Where chat manager has something like this :

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using UnityEngine.Networking;
    4.  
    5. public class Chat_Manager : NetworkBehaviour {
    6.  
    7.     public static Chat_Manager Instance;
    8.  
    9.     void Awake(){
    10.         Chat_Manager.Instance = this;
    11.     }
    12.  
    13.     [ClientCallbackAttribute]
    14.     void AddMsgToChat(String Msg){
    15.         // Here is how you manage each client to spawn the chat strings. Be it by instantiating or editing a value or whatever you want.
    16.     }
    17.  
    18.     [Server]
    19.     public void ServerChatMsg(string Msg){
    20.         AddMsgToChat(Msg);
    21.     }
    22.  
    23. }
    Now, the reason why I'm passing the string through a [server] attribute onto a [ClientCallbackAttribute] is just to show you how you could make it so that the server/host might store the message onto some .txt archive file or something while each clients wouldn't requires it. It might also be useful if you want the new clients which connect to the host to access some of the previous chat entries.

    I know this might not be the best for everyone, but it's something that works with Unet.
     
    Last edited: Nov 19, 2016
    freyalt likes this.