Search Unity

Question Understanding lag compensation

Discussion in 'NetCode for ECS' started by JZ_Focus, Apr 15, 2021.

  1. JZ_Focus

    JZ_Focus

    Joined:
    Nov 19, 2018
    Posts:
    24
    Hi,

    I'm trying to get a better understanding of how Netcode works within a Multiplayer FPS context, naturally DOTS Sample is a great place for getting a better understanding.

    Currently I'm looking into lag compensation, in the AbilityAutoRifle.cs, it takes the collision world of a certain tick. This tick is the tick that the shooting client rendered, I assume this is to 'rewind' the collision world and check the client's hit against the world the client 'saw' when it pressed the 'shoot' button.



    This seems to work fine (see image above) when I enter a Send/Receive delay of 0ms. When I enter a delay of about 100ms, the positions are very off (see image below) and so the hit reg will be abysmal. In the newest version of netcode we are also able to input an interpolation delay, this can be done via the 'CommandDataInterpolationDelay' I believe, however I'd like that to be confirmed as there is barely any documentation or info about it (mostly the netcode sample uses it).



    Now my question is, how would I go about applying proper lag compensation in something like DOTS Sample when I have a higher latency. Should this issue be fixed through lag compensation or are there other paths I am currently missing.

    Also, this is how I'm currently drawing the collider positions at the end of the ShootingPhase in AbilityAutoRifle.cs:

    Code (CSharp):
    1.  
    2. isServer = World.GetExistingSystem<>(ServerSimulationSystemGroup) != null;
    3.  
    4. ...
    5.  
    6. if (isServer)
    7. {
    8.     for (int i = 0; i < collWorld.NumBodies; i++)
    9.     {
    10.         if (hitColliderOwnerFromEntity.HasComponent(collWorld.Bodies[i].Entity))
    11.         {
    12.             var pos = collWorld.Bodies[i].WorldFromBody.pos;
    13.  
    14.             DebugDraw.Sphere(pos, 0.1f, UnityEngine.Color.cyan, 5f);
    15.         }
    16.     }
    17. }
    18. else
    19. {
    20.     for (int i = 0; i < collWorld.NumBodies; i++)
    21.     {
    22.         if (hitColliderOwnerFromEntity.HasComponent(collWorld.Bodies[i].Entity))
    23.         {
    24.             var pos = collWorld.Bodies[i].WorldFromBody.pos;
    25.  
    26.             DebugDraw.Sphere(pos, 0.1f, UnityEngine.Color.red, 5f);
    27.         }
    28.     }
    29. }
    30. }
     
    Last edited: Apr 15, 2021
  2. timjohansson

    timjohansson

    Unity Technologies

    Joined:
    Jul 13, 2016
    Posts:
    473
    The lag compensation has a limited number of ticks it allows you to roll back. This is to prevent high ping players from creating a bad experience for everyone else - instead the experience is a bit worse for the high ping player who has to lead targets when shooting.
    The problem is that if a low ping player is shot by a high ping player without limiting how far we roll back, the low ping player will be moved back a very long distance on the server to perform the raycast. That means the low ping player will be shot behind walls more frequently and further "in" the cover.
    The delay is applied on both send and receive btw - so 100ms is a ping of 200ms which when you add interpolation delay and command slack should put you above the max for how much we allow rolling back.

    No, the CommandDataInterpolationDelay is used on the server to get access to what interpolation delay the client had, you should *not* change that - it is intended to be read-only.
    In order to tweak what delay you use you need to create a singleton entity with a `ClientTickRate` component on the client and set `InterpolationTimeNetTicks` or `InterpolationTimeMS`. Use the static `NetworkTimeSystem.DefaultClientTickRate` as a starting point and modify that rather than creating a new ClientTickRate component.

    As already mentioned, if you tweak the lag compensation to give a better experience for high ping players you will make the experience worse for all other players. I would not recommend removing the limit on how much lag compensation you use - but you can tweak the limit to something that works better for your game.
    Right now it is not easy to do, you would have to modify `RawHistoryBuffer` and `RawHistoryBufferExtension` in PhysicsWorldHistory.cs
     
    borysovcorp likes this.
  3. JZ_Focus

    JZ_Focus

    Joined:
    Nov 19, 2018
    Posts:
    24
    Hi Tim, thank you very much for responding so rapidly!

    Alright, this explains alot already, I thought I was able to back as far as the CollisionHistory allowed (EDIT: I thought it was 32 ticks and not 16). I wanted to make sure I was able to perfectly hit the player with high ping and then cap it myself, but now I know you guys already take care of that.

    I am currently using the CommandDataInterpolationDelay purely as a read-only value. However with the setup from DOTS Sample I had to change the ghost owner component from the PlayerState from Interpolated to Owner predicted otherwise it didn't seem to update the delay field within the component (as it wasn't replicated?).

    If I am reading it right, the size is currently set to 16. With a simulation rate of 60 this would amount to a maximum ping of around 266ms (16.67ms x 16). Shouldn't that support a send/receive delay of 100ms as it would result in a RTT lower or near 266 (depending on processing time) and thus draw the collisions in their expected positions?
     
    Last edited: Apr 15, 2021
  4. timjohansson

    timjohansson

    Unity Technologies

    Joined:
    Jul 13, 2016
    Posts:
    473
    I don't remember exactly how it is setup, but the entity having the CommandDataInterpolationDelay needs to be owner predicted so it sounds like you probably found a bug in dots sample.

    The total interpolation delay is TargetCommandSlack (2 simulation ticks) + rtt + 4*jitter + interpolation delay (2 network send ticks).
    In dots sample simulation rate is 60Hz and send rate is 20 iirc, that would mean that your total delay is 200(rtt) + 2(cmd slack) * 16 + 2(interpolation) * 3(sim ticks per net tick) * 16 = 328 +some extra because your ping is not perfectly stable.
     
  5. JZ_Focus

    JZ_Focus

    Joined:
    Nov 19, 2018
    Posts:
    24
    Thanks for clarifying the way the delay works, I knew I had to be thinking too simply about it.

    I know DOTS Sample isn't fresh in your memory so maybe you won't recall, but I was wondering what the main reason was for the 'player' and 'character' to be separated. Though it offers the ability to destroy the character entity and start off with a clean slate, I was wondering if there were other perks to having those two separated.