Search Unity

Authoritative Multiplayer Racing using UNET

Discussion in 'UNet' started by jasielmacedo, May 22, 2017.

  1. jasielmacedo

    jasielmacedo

    Joined:
    Dec 11, 2010
    Posts:
    7
    Hello guys,
    I'm working on a racing based game multiplayer and to do this right (without cheat possibilities) i'm trying to do authoritative multiplayer.
    Valve have a lot of posts about multiplayer, sync and others staffs, but this is not a simple work.
    I decided to create this discussion because i want to share my discoveries and try with you to solve this millenarian question/problem.
    My english is rusty, but i'll try to do my best. (ignore grammar mistakes and feel free to correct me)

    When everyone talks about rigidbody authoritative sync one common mistake is link with player common sync. No, is not the same thing.

    And local multiplayer with photon is not authoritative, each player controls you own position and this is bad, because with cheat engine or some programs like that, one player can teleport to the end and win the race. (this is possible, i've tested)

    In the last weeks i've read a tons of posts about rigidbody sync, player sync, assetstore racing packs and every stuff around this topic, and i've dedicated my time trying to test and validate all solution, unfortunately without success.

    One interesting post about authoritative sync is from GenaSG:
    He created this script to move and interpolate the player authoritatively

    Using this logic and adapting for racing, the result process is:

    1. Client collect inputs
    2. Client Send to Server
    3. Client predict the inputs (this process is not simple like character movement because the results will occurs in the future)
    4. Client save snapshot with position, rotation, velocity, angular velocity in current frame.


    5. Server receive inputs
    6. Server process inputs (but again inputs applied cant generate exact position)
    7. Server send result position, rotation, velocity, angular velocity

    8. Client receive current server position
    9. Client compare received position with saved snapshot from past, if is wrong adjust location
    (Here is the problem)

    But, BUT, talking about rigidbody we cant rewind all inputs to predict real position like this code:

    Code (CSharp):
    1. //Owner client
    2.         //Server client reconciliation process should be executed in order to client's rotation and position with server values but do it without jittering
    3.         if (isLocalPlayer && !hasAuthority) {
    4.             //Update client's position and rotation with ones from server
    5.             _results.rotation = results.rotation;
    6.             _results.position = results.position;
    7.             int foundIndex = -1;
    8.             //Search recieved time stamp in client's inputs list
    9.             for(int index = 0; index < _inputsList.Count; index++){
    10.                 //If time stamp found run through all inputs starting from needed time stamp
    11.                 if(_inputsList[index].timeStamp > results.timeStamp){
    12.                     foundIndex = index;
    13.                     break;
    14.                 }
    15.             }
    16.             if(foundIndex ==-1){
    17.                 //Clear Inputs list if no needed records found
    18.                 while(_inputsList.Count != 0){
    19.                     _inputsList.RemoveAt(0);
    20.                 }
    21.                 return;
    22.             }
    23.             //Replay recorded inputs
    24.             for(int subIndex = foundIndex; subIndex < _inputsList.Count;subIndex++){
    25.                 _results.rotation = Rotate(_inputsList[subIndex],_results);
    26.                 _results.crouching = Crouch(_inputsList[subIndex],_results);
    27.                 _results.sprinting = Sprint(_inputsList[subIndex],_results);
    28.  
    29.                 _results.position = Move(_inputsList[subIndex],_results);
    30.             }
    31.             //Remove all inputs before time stamp
    32.             int targetCount = _inputsList.Count - foundIndex;
    33.             while(_inputsList.Count > targetCount){
    34.                 _inputsList.RemoveAt(0);
    35.             }
    36.         }
    I cant predict all movements inside one Tick Update because rigidbody needs time to process.

    And the most important thing, if the server and client execute the same inputs the results will not be the same because each one have particularities. If the server runs with 60FPS and client runs with 26 FPS the client car will jitter for a long time. Every movement will be corrected because like i said, the same inputs not generate the same results.

    For example, one player with 100ms of ping decide to make a fast curve and collide with wall, but 100ms is a lot of time, and server can process totally diferent and the curve in the server can be perfect and this will teleport the client creating the most frustrating experience ever.

    How can i solve that problem? Which the best solution?

    And finally how to sync physics behaviour in server and client?

    I'm considering to accept some position from client and use to reposition the server, but this will generate a lot of jittering for clients dummy inside others clients

    Any solution will be helpful, and any code snippet will be helpful too

    I will update this post with solutions and discoveries.

    [UPDATE 1]
    Maybe the best solution is:

    1. Client process inputs and calculate complex physics
    2. Client send location to server
    3 .Server receive location
    4. Server check if location is not strange (maybe a teleport out of bounds or cheating)
    5. Server send to all others clients the location

    Server doesn't perform all player inputs again, the server only check if the player position make sense
     
    Last edited: May 22, 2017
    JasonBruse and Whippets like this.
  2. donnysobonny

    donnysobonny

    Joined:
    Jan 24, 2013
    Posts:
    220
    So, cheat prevention in general is a complex topic, like most network-related topics are. In general though, you're asking the right questions and you seem to be on the right track.

    So the first thing here is, you're obviously planning on building a competitive game. In some cases, when you consider the development time that it takes to both implement and maintain cheat prevention; along with the potential hit that user experience can take due to cheat prevention (forced lag while input it sent, validated, and then applied) cheat prevention isn't worth implementing. In cases where you are building a competitive game though, that one or two players out of thousands that cheat can completely ruin the game for everyone. So it becomes necessary.

    With the above being said, it's important to understand that using an authoritative server layer to receive input, validate it, then apply it is the one-size-fits-all solution. It will always work, and it can be fairly easy to implement. However, as mentioned above it causes forced lag due to everything that the player does needing to be authenticated before it is applied. Not only that, but depending on how much you rely on this, things can get crazily complicated very quickly. Ultimately, this isn't always the most efficient way to implement cheat prevention.

    I recently started working on a racing game too, and stumbled into the same challenge that you are facing. Ultimately, I don't have an authoritative layer. I don't want one because in a high-speed-action game like a racing game, ANY latency would kill the user experience. So, I had to be more clever about how to prevent cheating. My solution is really quite simple:
    • the racing tracks in my game can fairly easily be measured for distance. This allows me to know roughly how much distance a car must travel to have done a lap of the track. This obviously isn't precise, because taking corners wide/tight can greatly effect the distance that you would travel to get around the track, but it does give us a good medium to measure whether the car has in-fact travelled enough distance to merit a "lap"
    • along with the above, i added some additional things to look out for. The most notable one is that for each track, I state a maximum average speed based on play-testing the track. I use this, along with the distance check mentioned above, to check that the car travelled enough distance and within a reasonable average speed to merit a lap
    The result for me is that the networking was incredibly simple. The client-side periodically sends the position/rotation of the car, while the server-side sends out these updates to all other players while at the same time recording the average speed and distance of the car on the server-side. This does mean that while a player is cheating, their car will clearly be doing strange things in the game, but their lap time etc will not be recorded and therefore the cheater will not be rewarded nor effect the game permanently. It's also possible for me to detect instances where the distance/average speed was questionable and ban the player using the above method.

    It took a lot of weighing in pros & cons along with understanding the game concept that I was building to come up with the above solution, ultimately though it shows that cheat prevention doesn't always have to negatively affect development and/or user experience. If you take the time to understand what it is that you need to prevent, there's usually a clever way to do it.

    Hopefully this helps, good luck!
     
    Last edited: May 22, 2017
    DBarlok, jasielmacedo and Whippets like this.
  3. jasielmacedo

    jasielmacedo

    Joined:
    Dec 11, 2010
    Posts:
    7
    This is an interesting way to solve that donnysobonny, maybe the best way, i guess.

    I'm really appreciate your solution because i'm considering to do that but i had my doubts.

    Every hard physics calculation can be made on client-side and send to server avoiding server to calculate complex physics. And like you said
    This solution avoid latency problems

    Yes my game is a competitive game, but without racing tracks limitations. This is the game by the way.
    Im the first moment i made with photon but i've migrated to unet for more control and security with dedicated server-side.

    Maybe your solution in this moment can be good and what i need to do is prevent players to cheating checking players location on server-side.

    Based on your solution, the process can be:

    1. Client process inputs and calculate complex physics
    2. Client send location to server
    3 .Server receive location
    4. Server check if location is not strange (maybe a teleport out of bounds or cheating)
    5. Server send to all others clients the location

    All others staffs like team scores is always server-side and any cheating player can compromise others players experience. Thsi kind of player will be kicked.

    Thank you donnysobonny
     
  4. donnysobonny

    donnysobonny

    Joined:
    Jan 24, 2013
    Posts:
    220
    No problem, I'm glad that I can help.

    This seems okay, but I would make a few suggestions:
    • you only need to do the complex physics calculations for your own car in the client-side. Other player cars will have had the complex calculation done by the owning player before their position etc was sent to the server-side. So make sure you are only calculating the physics on your own local car, and not on the remote player cars
    • your 4th point is pretty much where the challenge lies. For me, this is where i'm checking for distance/average speed, so if you were to use the same method this is where you would do it too. Otherwise, the success of your solution pretty much lies in how efficiently you can validate what is going on based on whatever variables you have available to you.
    Other than that, yeah you're on the right path. Good luck!
     
  5. Stanchion

    Stanchion

    Joined:
    Sep 30, 2014
    Posts:
    269
    You can do client side prediction for rigidbodies using the manual stepping in the Unity beta.
     
  6. jasielmacedo

    jasielmacedo

    Joined:
    Dec 11, 2010
    Posts:
    7
    Really? how can i do that?

    Have you a code snippet? i'm trying to search about manual stepping but i can't find any results.

    Can you send some link? will be helpful
     
  7. Jick87

    Jick87

    Joined:
    Oct 21, 2015
    Posts:
    124
    I think I have the basic concept with the code I have here but, as you can read in that thread, I don't quite have it working yet... It might be a good start though if maybe someone comes along and has some pointers on how to fix it.
     
  8. newlife

    newlife

    Joined:
    Jan 20, 2010
    Posts:
    1,081
    Hello @jasielmacedo,
    Im facing the same issues with my mobile racing game Real Drift Car Racing trying to implement multiplayer.
    In my case I don't need collisions between mutiplayer cars to be on, so it should be easier than the standard use case.
    Did you manage to find a solution to this problem?
    To my research, it seems that the simplest solution is to use photon Bolt like explained here https://doc.photonengine.com/en-us/bolt/current/community-wiki/extra-bits/use-cases in particular the use case "Client Auth, Predicted Movement With Server Side Sanity Checks With Commands".
    @donnysobonny, this solution seem very similar to the one that you proposed.
    What do you think?
     
  9. JasonBruse

    JasonBruse

    Joined:
    May 7, 2019
    Posts:
    5
    I know this is an old thread. I learned a lot from it.
    But I got a question: how does client process calculate complex physics?