Latency compensation with projectile weapons

Discussion in 'Multiplayer Networking' started by PrimeDerektive, Feb 9, 2012.

  1. PrimeDerektive

    PrimeDerektive

    Member

    Joined:
    Dec 13, 2009
    Messages:
    2,959
    I'm trying to figure out the best way to handle latency compensation with locally instantiated projectiles through RPC's. It's all authoritative, currently, I'm teleporting it. Simplified, it's something like:

    1)Shooting client instantiates rocket locally, sends RPC to server to do the "for real" rocket

    2)Server instantiates the rocket, but with a start position of:
    startPosition + direction*((Network.time-info.timeStamp)*velocity).
    Then sends an RPC to other clients (besides the owner) to create a rocket, with an additional float parameter of the original shooting client's timestamp (origTimeStamp)

    3)Remote clients instantiates the rocket, but with a start position of
    startPosition + direction*((Network.time-(info.timeStamp+origTimeStamp))*velocity)

    So I'm offsetting the starting position by a distance equal to the amount the rocket should have traveled in that amount of latency. Only the server's rocket can actually explode, and tell other clients where the explosion should be. This seems to be working pretty well, the only problem being, depending on latency, the shooting client might not be able to hit enemies at point blank, because the server's rocket is being created past it. I could fudge it with a raycast on the server, but I feel like that might lead to discrepancies with point-blank rockets.

    My next thought was to fudge it so server and remote client rockets have an increased velocity until they "catch up" with the original shooter's timestamp, but I'm not sure how to calculate it both what it should be, and how long it needs to stay at that velocity.
    Last edited: Feb 9, 2012
  2. PrimeDerektive

    PrimeDerektive

    Member

    Joined:
    Dec 13, 2009
    Messages:
    2,959
    After some tinkering, I think its:

    timetoCatchUp = (normalSpeed*delay)/(catchUpSpeed - normalSpeed);
    Last edited: Feb 9, 2012
  3. Johnnyr

    Johnnyr

    New Member

    Joined:
    Jun 1, 2009
    Messages:
    58
    Legend, can you tell me the reasons you decided to move to ulink? Does it handle networking in a better way? more automatically?, less worrying about each client having slightly different copies of the same things, such as position, etc?
  4. tasadar

    tasadar

    Member

    Joined:
    Nov 23, 2010
    Messages:
    155
    also other clients will see the projectile spawning not at the muzzle but some units away from it, a visual problem but can be solved easily.
    another thing is that i assume the client will send the startPosition, how will you prevent cheating here?
  5. fholm

    fholm

    Member

    Joined:
    Aug 20, 2011
    Messages:
    1,684
    This problem is called event synchronization. The basic problem statement is this:

    "When a client does something locally which needs to be re-played on the remote clients how do we make sure that this replay looks and behaves properly?"

    The most basic example of this is when your player jumps locally from the ground up to stand on a box or ledge instead. How do we make sure that the animation on the remote clients match the exact change in position and velocity that the jump gives us.

    Now I don't remember exactly how you have laid out your game legend411, what types of techniques it uses for smoothing out movement, compensating for lag when shooting, etc. But I will describe the basics on how to do this.

    First of I have to say that the approach you are using right now only really works in simple cases, when you have an isolated or single event such a rocket flying through the air. When you end up having a lot of different events, that need to interact together, that all use some sort of "approximation" algorithm it's all going to end up in one big mess.

    I assume you do some level of movement interpolation on your clients of remote entities. This is a good basis to start, we can name the current interpolation time of a remote entity it's "simulation time" or st for short. Simulation time only exists for remote entities, your local entity always runs at your local time, or lt.

    Simulation time is usually derived as this "st = networkTime - (updateRate * 2)".
    Local time is derived as "lt = networkTime"

    The process of re-playing events is best described as a step-by-step process, also going to use your rocket-problem for the description here:

    1. Client A shoots a rocket from position P0 at his current lt
    2. Client A sends his shoot command to the server
    3. The server ignores the lt of the client and re-distributes the command to all remote clients (now, depending on if the server is an actual player or not, more things might or might not need to be done on the server itself, assuming the server is a simple relay server right now)
    4. Client B receives the event
    5. Client B puts the event in a queue attached to the simulated Client A game object in his local copy of the world, he also labels the event with is own current lt
    6. Before every update cycle on the simulated Client A entity on Client B, Client B checks all the events in the event queue and replays all of them that have a lt value less then or equal to the st of the Client A entity.
  6. PrimeDerektive

    PrimeDerektive

    Member

    Joined:
    Dec 13, 2009
    Messages:
    2,959
    Yeah, that's why I was trying to figure out the formula for how long projectiles would need to be sped up to catch up to the shooting client on the server (rather than teleporting like I was doing initially) to where they should be on the server. I have it working pretty well now, with the formula I posted.

    The client doesn't send the startposition, all remote prefabs have the gunBarrel parented to the gun in the same place, so I only send the hit point and let each remote calc their own direction.

    I had a convo with fholm about the possibility of cheating with allowing clients to call their own shot directions, and we concluded its a non-issue. I don't know of any multiplayer game that handles aim rotation authoritative, it would be too costly on the server (hence punkbuster and aimbots in AAA gameS). I do do a small sanity check on the server to check the delta between the player's forward and the direction pointing to the hit point, to make sure they're not shooting behind their backs or rotating entirely too fast or whatever.

    The amount of work it would take to hack the game to mine enemy positions and create an aimbot would be non-trivial. If I get to that point, I'm probably rolling in dough.
    Last edited: Feb 11, 2012
  7. tasadar

    tasadar

    Member

    Joined:
    Nov 23, 2010
    Messages:
    155
    check this out : http://download.muchdifferent.com/ulink/Why_youll_love_uLink_2011-06-03.pdf

    legend411 : i am also toying with ulink and the sample entity interpolation code (which is the same with unitys sample code) is not behaving properly even with zero ping, despite it is a linear interpolation it is kindda moving irregularly, getting faster and slowing down at some interval. do you have any issues/experience with this?
    Last edited: Feb 11, 2012
  8. PrimeDerektive

    PrimeDerektive

    Member

    Joined:
    Dec 13, 2009
    Messages:
    2,959
    Do you mean uLinkSmoothCharacter, and/or uLickStrictCharacter or uLinkStrictPlatformer? they're actually quite different than the example scripts from the Unity Networking example. I'm currently using uLinkSmoothCharacter authoritatively, I've done tests with 8 friends with emulation set to 200 ping with 5% packet loss and have had no trouble. I do see some weird lag/skipping occasionally when I test on the same machine connected to myself though, I was never able to figure out why, but I don't plan on encouraging people to open two instances of the game and connecting to themself on the same rig though, so I consider it a non-issue :) (it works flawlessly over my LAN when I test with my laptop).

    If I had to guess, I would say it's because the raw CharacterController velocity is sent through UpdateState() 15 times a second, and targetDistance is never really interpolated, just smoothed out a bit with deltaTime.
    Last edited: Feb 11, 2012
  9. tasadar

    tasadar

    Member

    Joined:
    Nov 23, 2010
    Messages:
    155
    I mean the one used in the snowbox, thats uLinkStrictPlatformer i think. i also tested snowbox itself and it seems the same.
    does uLinkSmoothCharacter have any prediction code, i may have overlooked it, i thought it was only smoothing incoming data.
  10. PrimeDerektive

    PrimeDerektive

    Member

    Joined:
    Dec 13, 2009
    Messages:
    2,959
    Not really, its just smoothing and corrects if it detects a discrepancy. I added some code to do some extra sanity checking in Move().