Search Unity

Resolved Help with Reconnecting System

Discussion in 'Netcode for GameObjects' started by GuirieSanchez, Dec 22, 2022.

  1. GuirieSanchez

    GuirieSanchez

    Joined:
    Oct 12, 2021
    Posts:
    452
    I want only the clients that connected at the start of the game to be able to reconnect while denying access to clients that weren't present at the start of the game (even if they have the right host's local IP and/or password).

    To do this, I thought about using an identifier for each connected client and saving and keeping it on the host/server. This way, whenever a client leaves and another one connects, I can check if his identification number is the same as the ID number of the client that left before.

    What do you think it's the best way to accomplish this?


    (What I tried)
    I thought about using a dictionary with the
    clientId
    as the key, and the value for the info. But I realized that the
    clientId
    changes after they disconnect and connect later. For instance, let's say there are only 2 players, one is the host and the second one is the client. The host gets a
    clientId
    of 0, whereas the client gets a
    clientId
    of 1. If the client disconnects and connects again, then his
    clientId
    would be 2, if he repeats the process it'd be 3, and then 4, and so on. Therefore, there's no way for me to check if he was the same player that was connected before.

    Then I thought about gathering the client's local IP, but I believe it won't be so reliable if they disconnect from the wifi and reconnect back because the local IP might change (I may be mistaken).

    Is there any other parameter that I can use as a unique identifier for each client?
     
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,953
    You simply need to generate a "new Guid()" for each client, and save it to disk once created and if it exists, use that instead.

    Send this Guid to the server with the connection approval payload. Server then either allows all clients to connect (lobby) or checks if the player was previously connected (session in progress) by comparing the Guid from the client with those Guids available when the game session started.
     
    GuirieSanchez likes this.
  3. GuirieSanchez

    GuirieSanchez

    Joined:
    Oct 12, 2021
    Posts:
    452
    Hi, thank you! I just check (didn't know about it) and that's exactly what I was looking for.

    I just have a couple of questions. When do I have to create this
    new Guid()
    for the client? On connection approval? At the start of the game? If so, wouldn't it change after he quits the game and restart it? (since it'd be generating another
    new Guid()
    ?
     
  4. GuirieSanchez

    GuirieSanchez

    Joined:
    Oct 12, 2021
    Posts:
    452
    Ok, I kind of managed that. But now I'm facing a big problem:

    On the
    NetworkManager.ConnectionApprovalCallback
    I have to get access to the client's (intending to connect) information (I saved their GUID on a scriptable object, so that they can keep it in between sessions). What I don't know is to identify which client is connecting and access to that GUID in order to compare it against the server's stored clients' GUIDs.
     
  5. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,953
    Run new Guid() the first time the app is launched. ScriptableObject may not be the right place because either the guid is generated in the editor and thus the same for all players or it isn‘t saved because SO are readonly in builds.

    Anyhow when players first connect in the „lobby“ the server stores the guid and clientid in a list or dictionary.
    Once the game started connection approval takes a different code path where the client‘s guid from the payload is compared with the already stored guids in the list/dict. Only if it‘s in there the client can connect. Clientid will most likely be different so use the guid to identify specific players.
     
    GuirieSanchez likes this.
  6. GuirieSanchez

    GuirieSanchez

    Joined:
    Oct 12, 2021
    Posts:
    452
    I see. Thanks for the explanation.

    The payload
    Code (CSharp):
    1.  
    2.         public struct ConnectionApprovalRequest
    3.         {
    4.             public byte[] Payload;
    5.             public ulong ClientNetworkId;
    6.         }
    is inside the NetworkManager [from metadata]. I can't modify it in order to add the GUID there
     
  7. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,953
    See the manual. You're supposed to serialize your data into a byte array and assign it to Payload. You can serialize a class/struct to json with JsonUtility and then use System.Encoding to transform the json string into a byte array, and back.
     
    GuirieSanchez likes this.
  8. GuirieSanchez

    GuirieSanchez

    Joined:
    Oct 12, 2021
    Posts:
    452
    Thank you! I managed to do it :)

    Now I need to think about where to save the client Guid.
     
  9. GuirieSanchez

    GuirieSanchez

    Joined:
    Oct 12, 2021
    Posts:
    452
    By this, you were thinking about PlayerPrefs? Creating a new Guid(), saving it to PlayerPrefs, and then, whenever the player quits and starts the game again, check if PlayerPrefs.GetString(clientGUID) is not null (then use it), and if it is, then create a new Guid().
    Something like:
    Code (CSharp):
    1. public static string clientGUID
    2.         {
    3.             get => PlayerPrefs.GetString(KeyPrefix + nameof(clientGUID), null);
    4.             set => PlayerPrefs.SetString(KeyPrefix + nameof(clientGUID), value);
    5.         }
     
  10. GuirieSanchez

    GuirieSanchez

    Joined:
    Oct 12, 2021
    Posts:
    452
    Ok, I implemented it with the PlayerPrefs system and it works pretty nicely. Thank you!
    I also think it was pretty useful to get to know how to send data through the payload. I can think of a handful of cool stuff that I can do thanks to that.