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.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

How do I reconnect a player and have them control the same game object again.

Discussion in 'Multiplayer' started by LeetRooster, Jan 3, 2016.

  1. LeetRooster

    LeetRooster

    Joined:
    Jul 20, 2013
    Posts:
    18
    I was wondering if there was an identifier for a player which I can use to reconnect them and attach them to the same GameObject again. I was thinking of doing something like this by subclassing the NetworkManager. But this requires an identifier for the player, and to be able to get that again when they reconnect.

    I also nooped few OnServerDisconnect and OnServerRemovePlayer so that they don't destroy the player object. I want to keep the player in game, in the same position. But to give them control again when they reconnect.
    I'm not sure what identifier I need to tell that its the same player again reconnecting. The playerControllerId seems to refer to an index for multiple player within a connection (i.e. 2 players on the same computer, like in halo 2).
    The connectionId doesn't seem very useful and these indicies can get reused when other players connect and a new one can be created when the same player reconnects.
    IP address is also not an ideal way to do this. As you can have multiple players connect from different instances of the game on the same computer (i.e. when you are developing).
    Is there anything like a session token that gets created when a player connects to the server, and that would get reused when the player reconnects.

    Also, what would be a good way to do manual testing when running on a single computer for this. Would it be possible to run multiple player sessions like this on the same computer.

    Perhaps there isn't a built in way to do this? Maybe the only way is to implement your own session system, connect the player and authenticate them with their credentials and use that so that the server knows how to re-associate the reconnection to the player?
     
    wlwl2 likes this.
  2. Severos

    Severos

    Joined:
    Oct 2, 2015
    Posts:
    181
    Well, you kind of answered your own question, far as I know (which isn't much by the way) Unity doesn't have that very special identifier, so you can implement a login system with (username : password) and change your tracker to Dictionary<string,GameObject> where the string is the user name.
    Another way to do it is let client generate a random string and assign it to them self (make sure it's a long random one to avoid problems), and when connecting to server it can send a message telling server it already has an ID and make server give it Authority over the object with that ID.
     
    Scorr likes this.
  3. Scorr

    Scorr

    Joined:
    Jul 2, 2013
    Posts:
    73
    I had implemented this also using ip address, but like you said this causes problems with people connecting from the same network.

    I didn't think of attaching a GUID to the client until I read Severos' post above, and after searching if Unity has a way of generating these I found this:
    http://docs.unity3d.com/ScriptReference/SystemInfo-deviceUniqueIdentifier.html
    tl;dr: it says it generates a string that's guaranteed to be unique for every device.
    If you're only trying to check if it's the same player trying to reconnect, I think this would be ideal. That said I haven't tested it yet.

    Edit:
    One thing to note is that the first time calling this takes over a second (probably depends on cpu) to calculate the value. Subsequent calls (during the same runtime) are instant.

    I'm now trying to figure out how to call this on the client when connecting and passing it to the server during OnServerAddPlayer. Anyone else have ideas?
     
    Last edited: Jan 4, 2016
  4. Severos

    Severos

    Joined:
    Oct 2, 2015
    Posts:
    181
    Well, one way is to not use the normal way of spawning a player, you can use something like this:
    Code (CSharp):
    1. public class ConnectPlayerMessage : BaseMessage { //all network messages inherit from BaseMessage class.
    2.     public string id,username,password; //data to be sent in the message
    3.     [System/NonSerializable]
    4.     public static short Msg_ConnectPlayerType() {return short.MaxValue();} //when you register a message handler it needs an id, usually people store all custom ids in a separated class, but I like it this way.
    5. }
    note that the code isn't bug free as I've written it from memory.
    username and password are for authentication, and if they were logged in then they'll have an id to send and you can load the data.
     
    Scorr likes this.
  5. Scorr

    Scorr

    Joined:
    Jul 2, 2013
    Posts:
    73
    I think you're right, having the player send a message on connection to authenticate itself seems like way to go.

    If you don't need accounts though, sending the deviceUniqueIdentifier seems like a good alternative.
     
  6. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    ClientScene.AddPlayer() has a version that takes a a message:

    public static bool AddPlayer(NetworkConnection readyConn, short playerControllerId, MessageBase extraMessage)

    So the callback OnServerAddPlayer will be passed the message:

    public virtual void OnServerAddPlayer(NetworkConnection conn, short playerControllerId, NetworkReader extraMessageReader)

    This can be used for login information.
     
  7. LeetRooster

    LeetRooster

    Joined:
    Jul 20, 2013
    Posts:
    18
    Thanks everyone for the reply. I'm going to give thee system unique identifier a try. I would eventually have some sort of account/login system for the game, but for now something like this should work well for prototyping.

    The only other issues that I see with it, are that it won't work well for multiple client instances running on the same machine. But I can add a command line arg or something for this, to identify each player separately. This use case only really applies to dev/debugging.

    Also the other issue is security. It might be possible to spoof as another player if you can figure out their identifier. That could be solved with SSL/encryption. I'm not sure to what extend unity packets are encrypted.

    Though, thats not a big deal for a prototype. But for a final game ssl/encryption would be needed for implementing a login system regardless.
     
  8. Severos

    Severos

    Joined:
    Oct 2, 2015
    Posts:
    181
    I'm actually building a Login system that disconnects player if didn't authenticate within 5 seconds (can change time), I'm almost done with the basic thing and I'm testing it, probably will put code in thread later today or tomorrow, you can find the thread here:
    http://forum.unity3d.com/threads/login-system-for-online-multiplayer-game.377106

    As for creating a Unique identifier for each object, I have a simple method but if you're going to get mass number of players it might be resource consuming, you can use the SHA512 of username/password/salt + time in ticks, I really doubt someone would be able to guess exactly at which tick the client connected to try and brute force it, well maybe SHA512 is too much, pretty sure SHA256 can do the job.
     
  9. Scorr

    Scorr

    Joined:
    Jul 2, 2013
    Posts:
    73
    This is really useful, thanks!

    True, after implementing this it's more annoying to debug for me as well. I'm considering removing this check for dev builds and turning it back on for player builds.

    You're right that it won't work for multiple client instances, and like you said it depends on the use case. If you want to prevent people multiboxing on your server, allowing one person to gain an advantage by being multiple players at the same time, I think you'd want to avoid multiple client instances (among other things). This is if you aren't using an account system of course.

    If just creating a Unique Identifier is the goal, you could also use (System.)Guid.NewGuid(). Though I don't know how safe it is in regards to spoofing.
     
  10. fedecaccia

    fedecaccia

    Joined:
    Apr 5, 2015
    Posts:
    14
    Is there some implementation with user/pass?
     
  11. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Unet does not have a built in username/password feature. You'll have to create that functionality yourself.
     
    fedecaccia likes this.
  12. fedecaccia

    fedecaccia

    Joined:
    Apr 5, 2015
    Posts:
    14
    Can you provide me some link or some sources of information to implement it?
    I'm reading the Unity Manual but I don't fully understand how to do it.
    Thanks!
     
  13. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Unfortunately I cannot because I'm not aware of any. When I was using Unet this is what I did. It may not apply to your situation.

    * Create a separate login server and client scene that uses NetworkServerSimple.
    * On successful login, the server sends the client a random session ID and also stores it in the database, and the client places the username and session ID on an object with DontDestroyOnLoad set.
    * I disconnect the client from the login server and change scenes to the gameplay scene, where the client then connects to the gameplay server. The server then spawns the Player GameObject for the new client.
    * The client then sends a Command to the server with the username and session ID. The server checks those against the database, if invalid the client is disconnected, if valid the server starts setting up the character for the client.

    In my set up, the Player GameObject isn't the actual character that the player controls, but instead just for logging in and sending Commands to the server. The actual character the player controls is a separate object spawned by the server, based on what the database says that player has.
     
    wlwl2 likes this.