Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

Unity Multiplayer Unet server-authoritative movement with client-side prediction and reconciliation

Discussion in 'Connected Games' started by GenaSG, Aug 24, 2015.

  1. hakankaraduman

    hakankaraduman

    Joined:
    Aug 27, 2012
    Posts:
    336
    Hi, you can also click to errors to open related lines and change from Input.GetButtonDown("<buttonName") to Input.GetKeyDown(KeyCode.<KeyName>) to get rid of the input errors.
     
  2. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    642
    The only animation that should be determined client-side is movement animation, when it comes to an authoritative server. Even still, with the setup provided in this thread, client-side animation is unreliable. 1. CharacterController velocity has never been reliable with Unity. 2. Even if the CharacterController velocity was reliable, at some point the velocity of the CC will not match between all three (server, local player, other clients). As far as other animations, the server should have complete control over them (shooting, picking something up, using an item, etc) because the server controls whether or not these things can happen. i.e. checking to see if a player actually has an item in their inventory, before using it, and thus processing the animation to use the item.

    In any case, no, with the system that @GenaSG has provided, client-side movement animation doesn't work properly. Player A's local player GameObject animates properly, but the server and other clients do not have the proper movement animation for the Player A's GameObject on their instances.
     
  3. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    642
    BUMP...still hoping to find a solution for reliable server-authoritative animations using this system.
     
    rikey likes this.
  4. iCode

    iCode

    Joined:
    May 25, 2013
    Posts:
    32
    Sorry to bring back an older thread. Unfortunately, this post is the best resource when it comes to authoritative movement in UNET.
    I wanted to say thank you for the code, it has been an awesome resource to learn from. I have been going through the code, and i also read the article that was in the original post. My question is this, is it true that this code does NOT implement the fourth series of the article:
    http://www.gabrielgambetta.com/fpm4.html
    I was looking at the shoot functionality, and didn't see any of the concepts discussed in the above link. I may be mistaken though?
     
  5. GenaSG

    GenaSG

    Joined:
    Apr 19, 2014
    Posts:
    103
    Hello @iCode,
    Thank you for kind words :). No I haven't done hit registration part in scope of this project. But from my experience with my main project I can say that it's pretty tricky to do in unity using this kind of approach. You see client-side interpolation is just an approximation of other client's position/rotation. So other engines, namely Source, IW/id tech3, this issue mitigated by frequent updates. So even relatively fast moving target can be hit. With unity it's different story, I didn't find a possibility to have 64Hz update rate. So hit registration would be hit or miss, no pun intended.
    So what I've done in my current project.
    I send input information on change from client to server and to other clients(via server). So the same code would be executed on all networked clients. Also I send results (position and rotation) periodically(e.g. every 500 ms). Those results evaluated by the server and being updated by server on all of the clients when needed.
    So speed hacks, teleports, wouldn't work. If I remember correctly this is Generalised Client-Server model(ut2004, possibly UT3).
    I use client side hit detection with server side validation. So shot event saved in the list (with shotID) both on shooting client and server. When client detects a hit it sends shotID info to server for validation. At this moment server only validates if it even was possible for bullet to be in the hit position and if hit client is in the specific radius from that point. I'll improve this approach later. But right now I already have some basic shot validation. Only shots that was registered on server can be validated. So no ROF or ammo hack would work.
    I hope this would be helpful for you.

    P.S. I wrote this post and forum almost screwed it up. Session timeout.
     
  6. iCode

    iCode

    Joined:
    May 25, 2013
    Posts:
    32
    Sure thing! Thanks for your response.
    I am still learning so i just want to make sure i understand you correctly. I have been reading on Lag compensation and came across valve's solution:
    https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking
    From that article they do this:
    "The lag compensation system keeps a history of all recent player positions for one second. If a user command is executed, the server estimates at what time the command was created as follows:
    Command Execution Time = Current Server Time - Packet Latency - Client View Interpolation
    Then the server moves all other players - only players - back to where they were at the command execution time. The user command is executed and the hit is detected correctly. After the user command has been processed, the players revert to their original positions."

    I trust your opinion over my on this subject, so in your opinion, this cant be done, or would be "tricky" to do in Unity?
    Thanks again!!
     
  7. GenaSG

    GenaSG

    Joined:
    Apr 19, 2014
    Posts:
    103
    I wouldn't say it's impossible. Heck, I did it myself. But I didn't get good enough results. It would work for large targets with large hitboxes, but not for arena like FPS. I mean in Unity, not general approach. And if you'd take a look on networking tutorials (I bet you did it already ;) ) you'd see that most of them use a lot of approximations. And approximations with such big margins is not good for server-side hit detection. Also one more point. Use Lerp(Slerp) correctly if you want to have more or less sane hit detection. I'm talking about Mathf.Lerp(startPosition,targetPosition,fraction) instead of Mathf.Lerp(transform.position,targetPosition,speed * Time.deltaTime).
     
  8. GrandAlchemist

    GrandAlchemist

    Joined:
    May 21, 2014
    Posts:
    9
    Hey there! I don't mean to butt-in... I was just wondering if you have tried increasing the Network Manager Sendrate. It can be found under Edit>Project Settings>Network.

    I assume this is the tickrate/refresh rate of the server - and if so, would increasing this value also increase the accuracy of server-side hit detection? The default value is a measely 15 intervals per second, which seems low...

    Also, would hacking/cheating be a concern while using client side hit detection with server side validation? I am still a novice to network programming, and this seems like a simpler way to go.
     
  9. jessejarvis

    jessejarvis

    Joined:
    Aug 9, 2013
    Posts:
    282
    I am currently using Ootii's Camera system and have Rotate Anchor set, how can I sync the character rotation to sync to this?

    Edit: More or less, how do I send the player's rotation to the server to get set? I'm looking in NetworkPawn.cs and NetworkMovement.cs but not sure where to set it.
     
    Last edited: Feb 17, 2017
  10. GenaSG

    GenaSG

    Joined:
    Apr 19, 2014
    Posts:
    103
    Playing with sendrate helps to some degree. It can be tuned to get acceptable results, but as I wrote, it's all just approximations so there would edge cases. Which usually leads to bad gaming experience. Don't forget that increased sendrate leads to increased network traffic which can potentially increase network latency.
    Regarding cheaters. It's always an uphill battle. There's no 100 percent cheating resistant approach. From my point of view the best way is to have "skill" based match making system and more or less robust serverside validation. So cheaters would end up playing with other cheaters.
    It's possible to validate movement, ammo, basic weapon statistics but it's really hard to protect against aimbots and wallhacks. So just let them check who has the best hacks. Preferably separately from non-hacking players.
     
    GrandAlchemist likes this.
  11. GenaSG

    GenaSG

    Joined:
    Apr 19, 2014
    Posts:
    103
    Haven't checked this project in a while. So can't help at the moment. Sorry man.
     
  12. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    1,942
    I might be late for the party, but I'll have to ask - Is it worth to use this project as an example of server-authoritative movement, without any like animations\record\playback features, and try to implement something similar?

    E.g. simplistic movement, prediciton and reconciliation.

    Or there's a better ways of doing this?

    As far as I understood, main problem of this example is low tickrate issue, right?
     
  13. GenaSG

    GenaSG

    Joined:
    Apr 19, 2014
    Posts:
    103
    Hello.
    It's tricky to make animation play exactly how it's needed for this kind of system.
    But you can implement history recorder for position/rotation/scale of player's colliders and iterate through records during reconsiliation process.
    And, of course, it really depends on what kind of game you're developing. Maybe you just don't need this system at all.
    Hope it's helpful.
     
    xVergilx likes this.
  14. Zincord

    Zincord

    Joined:
    Dec 21, 2013
    Posts:
    14
    Very good! Except that I needed something more precise, could you help me?
    I have a problem with latency, in the client it stays way ahead of the server ...

    I have been working on a small multiplayer. My problem is that I want my bullets to be slow moving so the standard raycast tricks that are normally used in multiplayer games don't apply in my case.

    I do have a system for hit detection that is handled by the server but this results in bullets hitting on the server and damaging a player but on the clients screen the bullet was no where near them making it effectively impossible to dodge and results in the player feeling cheated quite frequently.


    Do you know of any way to resolve this situation?

    It would look something like this: http://www.kinematicsoup.com/news/2017/5/30/multiplayerprediction
     
    Last edited: Sep 21, 2017
    Leoo likes this.
  15. itsDrew

    itsDrew

    Joined:
    Aug 16, 2017
    Posts:
    32
    Thank you thank you thank you. Currently making a 2D game based purely on physics and collisions. I read the same articles that you posted here (when you originally posted this) and they were a huge help in understanding how I needed to go about writing the authoritative server, but I didn't know how to implement it. I chopped up your networkPawn and networkMovement scripts, spent a few hours understanding how they work, and my initial implementation looks like its working exactly as I want it to. Great stuff dude.
     
    GenaSG likes this.
  16. GenaSG

    GenaSG

    Joined:
    Apr 19, 2014
    Posts:
    103
    Thank you for kind words. Glad to know that it helped you.
    Cheers.
     
  17. wobes

    wobes

    Joined:
    Mar 9, 2013
    Posts:
    678
    Hey, is there any possibility to move Camera rotation in Update(); instead of FixedUpdate()? thanks. Because the camera seems to be laggy and dependent on Timestep.
     
  18. GenaSG

    GenaSG

    Joined:
    Apr 19, 2014
    Posts:
    103
    Hello,
    For this kind of solution to work correctly updates should be frame independent. What you can do to remove choppiness is to add additional rotation calculation in update loop. But don't send any network updates in it. I'm not 100% sure if it will not break consistancy.
    Cheers
     
    wobes likes this.
  19. wobes

    wobes

    Joined:
    Mar 9, 2013
    Posts:
    678
    Thank you.
     
    GenaSG likes this.
  20. rgeko

    rgeko

    Joined:
    Aug 3, 2014
    Posts:
    8
    Hi GenaSG,
    I've try your code, is fantastic.

    I made some changes to the pawn and movement code to adapt them to my project.

    I'm struggle with rotation of Y axis. I have a simple cube that need to rotate on Y axis when i press the "Horizontal" inputs, all work fine but i dont understend why the Y axis back slowly to 0 when i release the button, seems like not save my last rotation.

    Link of scripts if can help:
    https://pastebin.com/nSF7LEH0 - NetworkMovement
    https://pastebin.com/SyJCyCvs - NetworkPawn

    Hope you can help me to understand what i did wrong.

    Regards.

    -UPDATE: seems ive found the problem, but i dont know if is the right way to do;
    in NetworkPawn -> Rotate() the public Quaternion (i've called it pTrnsfRotation) seems not save the current rotation.
    Ive add a line in Rotate() with pTrnsfRotation = PlayerTrnsf.rotation; (PlayerTrnsf is the public transform of NetworkPawn).
    With this new line seems ive solved the problem of the last rotation (before was every time 0,0,0).

    -RE-UPDATE: I've found a problem with my edited code, the player position have some bug on client side, im re-write it.
    I have some question (probably stupid), i've edits only the Move and Rotate function with my code, can the FixedUpdate make lag of position on client side? Because i've got some lag issues on client about position.

    If i move the player by means of transform.translate instead character.Move i could have problems?

    ps. Probably has nothing to do with multiplayer, but in the singleplayer the fixedupdate works without problems

    Thanks for your code, sorry if i waste your time.
     
    Last edited: Mar 2, 2018
    GenaSG likes this.
  21. rgeko

    rgeko

    Joined:
    Aug 3, 2014
    Posts:
    8
    Hi,
    I've found the problem about client position lag.
    Inside NetworkPawn -> UpdatePosition() i've replaced characterController.Move (newPosition - pawn.position) with Pawn.Translate(newPosition - pawn.position), this seems cause lag of position after some seconds.

    Now with characterController.Move() inside UpdatePostion() seems work fine but inside NetworkPawn -> Move() i need the Pawn.Translate() to move and steer the object. This cause some problem with the camera, it start a bit to flip (the camera is inside the cube parent).

    I will continue to work on the code, eventually someone know how to use characterController.Move() like if was transform.Translate()?

    I will update this post if i found the solution to the problem.

    Regards.
     
  22. wobes

    wobes

    Joined:
    Mar 9, 2013
    Posts:
    678
    Translate will ignore collision.
     
  23. rgeko

    rgeko

    Joined:
    Aug 3, 2014
    Posts:
    8
    Hi wobes,
    Thanks for your reply, there is the possibility to use characterController.Move() instead transform.Translate() with the same features?
     
  24. wobes

    wobes

    Joined:
    Mar 9, 2013
    Posts:
    678
    Hello. Well, actually Move() is the same as Translate() but Move() processes collision while moving the object in each frame. You may try to use Translate() and OnControllerColliderHit() for collision purposes.
     
    rgeko likes this.
  25. rgeko

    rgeko

    Joined:
    Aug 3, 2014
    Posts:
    8
    If i try to use Move() the cube not steering like when i use Translate(), i think they work differently.

    if i can not find a solution about Move() i will have to use Translate() and OnControllerColliderHit().
     
  26. wobes

    wobes

    Joined:
    Mar 9, 2013
    Posts:
    678
    Could you share two pieces of code? Move and Translate, I'll take a look
     
  27. rgeko

    rgeko

    Joined:
    Aug 3, 2014
    Posts:
    8
    Code (CSharp):
    1.  
    2.     public override Vector3 Move (Inputs inputs, Results current)
    3.     {
    4.         pawn.position = current.position;
    5.         movementFactor = Mathf.Lerp (movementFactor, inputs.forward, Time.deltaTime / movementThresold);
    6.  
    7.         Vector3 frwd = new Vector3 (0f, 0f, movementFactor * speed); // Move()
    8.         characterController.Move (frwd); // Move()
    9.  
    10.         transform.Translate (0f, 0f, movementFactor * speed); // Translate()
    11.  
    12.         if (inputs.forward > 0.5f) {
    13.             speed = 0.1f;
    14.         }
    15.         if (movementFactor < 0.02f && inputs.forward < 0.1f) {
    16.             speed = 0 ;
    17.         }
    18.          
    19.         return pawn.position;
    20.     }
    21.  
    obviously i not use Translate when i use Move, is only to show the entire code without split it
     
    Last edited: Mar 3, 2018
  28. wobes

    wobes

    Joined:
    Mar 9, 2013
    Posts:
    678
    Try this:
    Code (CSharp):
    1. Vector3 frwd = new Vector3 (0f, 0f, movementFactor * speed);
    2. frwd = transform.TransformDirection(frwd);
    3. characterController.Move (frwd);
     
    rgeko likes this.
  29. rgeko

    rgeko

    Joined:
    Aug 3, 2014
    Posts:
    8
    Work fine, really thanks mate :)
    I appreciate you help :)
     
    wobes likes this.
  30. wobes

    wobes

    Joined:
    Mar 9, 2013
    Posts:
    678
    You are welcome ;)
     
  31. Dreamer

    Dreamer

    Joined:
    Mar 8, 2011
    Posts:
    64
    Thank you for the solution. I have tested it. And looks good!
    But there is a issue. It seems that the movement lag will be 4 times than the actual lag.
    For example, if the lag is 500ms. Then it will take 2000ms for the object to reach the destination. If its 1000ms, it will take 4000ms. Is only me having this issue?
     
  32. GenaSG

    GenaSG

    Joined:
    Apr 19, 2014
    Posts:
    103
    Hello Dreamer.
    Yep that’s inheritant problem of all interpolation algorithms. To be smooth it has to have several values saved in the buffer for cases when one or several packets lost.
    I’m working on new model which will not have this flow. Don’t have any estimates though.
    Cheers
     
  33. Dreamer

    Dreamer

    Joined:
    Mar 8, 2011
    Posts:
    64
    Hi GenaSG,

    When I'm trying to dig and solve it. I find there is one thing that causes the delay.
    In void FixedUpdate(), the codes to be only run on standalone server.

    //Check if there is atleast one record in inputs list
    if(_inputsList.Count == 0){
    return;
    }


    I output the _inputsList.Count. And find the number is always >2. And only increasing. When this number getting bigger and bigger, the delay is getting worse and worse. Some times can get to 100+.

    Do you think there is a way to solve it? When it's >=2 and do something or it will only play the movement on server that's out of date.
     
  34. GenaSG

    GenaSG

    Joined:
    Apr 19, 2014
    Posts:
    103
    Hello and thanks.
    I’m not sure if I’ll get my hands on this issue any time soon. If you have a fix for it please make a merge request.
     
  35. fonko

    fonko

    Joined:
    Mar 20, 2014
    Posts:
    23
    hey i'm planning on doing a simple multiplayer game with players that hit each other, this seems like AN OVERKILL but i think i will learn a lot by going through it !!! so thanks in advance for your work!
     
    GenaSG likes this.
  36. validname1

    validname1

    Joined:
    Feb 1, 2018
    Posts:
    23
    Thanks for this wonderful resource. Managed to get it working on my 2d game with rigidbodies.

    In the end I did end up completely redoing it from scratch and used the reliable channel instead, but your example helped the idea "click" for me.
     
    GenaSG likes this.
  37. LenarVakhitov

    LenarVakhitov

    Joined:
    Mar 21, 2018
    Posts:
    2
    Hello, I have a question. I do this: I have 3 copies of the game, a server and 2 clients, create a server, connect the first client, everything is fine, and when I connect the second client, he sees the position of the first client in coordinates (0,0,0). But when I move the first client, the position of the first client is normalized and everything is fine. I do not understand this is bug or should it be ??
     
  38. GenaSG

    GenaSG

    Joined:
    Apr 19, 2014
    Posts:
    103
    Haven't touched this code for ages). Take a look if position has periodic updates and not only on change updates.
     
  39. newlife

    newlife

    Joined:
    Jan 20, 2010
    Posts:
    781
    Hello @GenaSG, thank you for this great source of information regarding multiplayer.
    I would like to ask your opinion regarding multiplayer for a mobile racing game, keeping in mind that Unet is deprecated.
    Which is the most suitable, easy to implement, authoritative and COMPLETE solution for multiplayer in a mobile racing game that doesn't need collision between multiplayer cars?
    Till now, I had a look to photon Bolt, gamelift and playfab. Recently I had also a look to spatialOS, but it seems that the mobile support is still in alpha stage.
    Do you have any suggestion?
     
  40. GenaSG

    GenaSG

    Joined:
    Apr 19, 2014
    Posts:
    103
    Hello,
    Haven't work with multiplayer lately :(. And I haven't tried new networking yet. I'd say, stick with UNET for now. I don't thing that new networking would be production ready any time soon. Sorry, I can't help you with anything else. Wish you luck ).
     
  41. VictorZed

    VictorZed

    Joined:
    Dec 24, 2015
    Posts:
    22
    Watch my video :)