Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

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

Discussion in 'UNet' started by GenaSG, Aug 24, 2015.

  1. hakankaraduman

    hakankaraduman

    Joined:
    Aug 27, 2012
    Posts:
    353
    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:
    683
    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:
    683
    BUMP...still hoping to find a solution for reliable server-authoritative animations using this system.
     
    Deleted User likes this.
  4. iCode

    iCode

    Joined:
    May 25, 2013
    Posts:
    33
    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:
    111
    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:
    33
    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:
    111
    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:
    10
    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:
    303
    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:
    111
    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:
    111
    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:
    3,296
    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:
    111
    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:
    111
    Thank you for kind words. Glad to know that it helped you.
    Cheers.
     
  17. Deleted User

    Deleted User

    Guest

    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:
    111
    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
     
    Deleted User likes this.
  19. Deleted User

    Deleted User

    Guest

    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. Deleted User

    Deleted User

    Guest

    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. Deleted User

    Deleted User

    Guest

    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. Deleted User

    Deleted User

    Guest

    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. Deleted User

    Deleted User

    Guest

    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 :)
     
    Deleted User likes this.
  30. Deleted User

    Deleted User

    Guest

    You are welcome ;)
     
  31. Dreamer

    Dreamer

    Joined:
    Mar 8, 2011
    Posts:
    67
    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:
    111
    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:
    67
    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:
    111
    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:
    26
    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:
    3
    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:
    111
    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:
    1,064
    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:
    111
    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. ep1s0de

    ep1s0de

    Joined:
    Dec 24, 2015
    Posts:
    168
    Watch my video :)
     
    GenaSG likes this.
  42. GenaSG

    GenaSG

    Joined:
    Apr 19, 2014
    Posts:
    111
    Nice one. I'm playing around with Mirror networking for unity. It's an open source implementation of UNET with multiple fixes. Right now I have some solutions but frankly I'm not very happy with those. They are kinda complicated and not very logical(because of HLAPI limitations). I'm trying to make it more unity native(e.g. networked character controller). If I'd get something interesting I'll share it here.
     
  43. GenaSG

    GenaSG

    Joined:
    Apr 19, 2014
    Posts:
    111
    Somehow it's funny. I constantly get links to this thread when I'm searching for server authoritative networking solution for unity3d. Is it that bad? I mean new networking from unity is still years away and there are no solutions to this problem beside zapnet and (crippled by photon )Bolt. Saw one open source solution which is as convoluted as mine current approach(with network entities, blackjack... you get the reference :) ).
    P.S. Just a rant, move along, nothing to see here.
     
  44. ep1s0de

    ep1s0de

    Joined:
    Dec 24, 2015
    Posts:
    168

    Player movement based on commands (UserCommand)
    Client side (main)
    1. You create a command with input data (tick number, strength of keystrokes, which buttons are pressed, etc.).
    2. You make a player movement based on the command
    3. You write to the buffer the current position, the command for subsequent verification when receiving the result from the server
    3. Buffering 3-4 commands before sending
    4. You send it to the server, reset the command buffer and then return to step 1

    Server side
    1. Accept the command
    2. You make a movement on the received command buffer
    3. Send the result back to the client

    Client side (consistency check)
    1. We accept the result of the movement from the server
    2. Get the position from the buffer by tick number and compare, if it is not equal to the server position, then teleport the player to the server position and reset the buffer


    I read the article from Gabriel Gambetta 2 times and looked at the description of how the player moves in the Source engine and I immediately understood the algorithm that I needed to write.

    Look at the links and read carefully...
    https://www.gabrielgambetta.com/client-server-game-architecture.html
    https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking
     
  45. GenaSG

    GenaSG

    Joined:
    Apr 19, 2014
    Posts:
    111
    If you’d read through the thread you will find that you aren’t the only one who’s using Gabriel’s awesome blog or source engine documentation. There are different approaches to this issue with different pros and cons. For example Unreal’s generalized client server model. Second thing, as it already has been mentioned in this thread sending inputs every frame at least in scope of UNET/Mirror is a bad idea. I know, I tried it multiple times. Third thing, have you tested your solution with bad network? I mean it all works fine on good network connection, especially client side interpolation but crumbles on bad connection with unstable latency and packets being dropped. Fourth thing, how about sharing your code with the community? Is your solution good enough to share. Will you share it? If not so what’s the point of writing “that’s easy”. No it’s not, multiplayer never has been an easy thing to implement. How many are there competitive shooters or twitch shooters made and released with Unity3d?
     
    Jos-Yule likes this.
  46. ep1s0de

    ep1s0de

    Joined:
    Dec 24, 2015
    Posts:
    168
    i have shared old source code in my thread
    https://forum.unity.com/threads/raknet-networking-solution.700619/
    https://github.com/ep1s0de3/RakNet_Networking
     
  47. GenaSG

    GenaSG

    Joined:
    Apr 19, 2014
    Posts:
    111
  48. qbvbsite

    qbvbsite

    Joined:
    Feb 19, 2013
    Posts:
    83
    Just wanted to thank you for posting your source code (like you mentioned it's one of the better resources for Unity Server Authoritative Networking). Mainly I used the NetworkMovement.cs as a jumping-off point to implement client prediction in my game and works great. Still need to do some tweaking to smooth out the latency/dropped packet issue but it's getting there (It's 100% smooth with no latency and pretty acceptable with up to 100ms).

    For others doing Authoritative servers that don't want to use UNet check-out LiteNetLib which is open source and works great. It does require more programming to implement but is well worth it IMO. I also took the route of doing a console version of the server rather than tie it to Unity, that's also a fun project for anyone looking for a challange.
     
    Last edited: Oct 27, 2020
  49. qbvbsite

    qbvbsite

    Joined:
    Feb 19, 2013
    Posts:
    83
    Just a follow-up to my previous post, as stated in the thread this resource here is awesome: https://gafferongames.com/post/deterministic_lockstep/ . Using the information in that post, this thread, and various other resources mentioned above I now have my project working with pretty horrible latency and packet-loss (300-500ms latency and 30% packet loss) and is smooth both as the Hero or Observer. Do note I'm doing a 2D Isometric game and currently only sending movement inputs. Here are some takeaways some people might find helpful:
    • Update position in FixedUpdate using MovePosition (or equivalent) and not transform.position. This makes sure colliders work correctly
    • Don't use Lerp for player movement, personally (At Least For 2D), I found it helped only when there was another underlying issue and once that issue was fixed the Lerp looked worst than just using MovePosition(position).
    • For Client-Side Prediction make sure that the server processes inputs in the exactly same way to make replay easier and position drift to a minimum. My 2D game movement was pretty easy as it's not a 3D simulation and the huge win for me was not using Time.delta when moving the player on the server. I instead used a determined value (since inputs only run on a fixed update I knew the exact amount of time between inputs). Once this was implemented my client-side / server positions were near perfect
    • Send all client/server movement updates via Unreliable UDP for speed and smoothness. I was having some issues once latency got above 200 and packet-loss of 10% and then realized I was sending all packets ReliableUnordered. Once I changed it to Unreliable my gameplay was much smoother and now it handles 500+ latency and 30% packet-loss like a champ. You may wonder how this works and it has to do client input buffering and having the client send past inputs in more than one packet.
    Hope those points help, I should note at this point in time I have not optimized packet size/bandwidth or stress tested it but atm it moving in the right direction. Also if you didn't read my previous post my server is a custom C# console application that makes use of LiteNetLimp for Networking, Grid/Quadtree for Collision/Locational Broadcasts, and Differ (C# port) for Testing Collisions. If anyone has any questions I'm happy to answer them.
     
    Last edited: Oct 29, 2020