Search Unity

Are built-in ticks reliable enough for prediction-reconciliation?

Discussion in 'Netcode for GameObjects' started by duckburger, Dec 14, 2022.

  1. duckburger

    duckburger

    Joined:
    Dec 7, 2016
    Posts:
    9
    Hi! I'm looking into building a 2d physics prediction-reconciliation system on top of Netcode for GameObjects and for that I need to add a tick number to each packet that I send to the server and then back. Would the
    NetworkManager.Singleton.ServerTime.Tick and NetworkManager.Singleton.LocalTime.Tick be reliable enough for this purpose?

    Thanks!
     
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,892
    Define "reliable".

    It's not suddenly going from 100 to 120 or something, skipping numbers.
    Both Server and Local time ticks will differ obviously.
    Ticks progress at a fixed rate specified in the NetworkManager settings.
     
  3. duckburger

    duckburger

    Joined:
    Dec 7, 2016
    Posts:
    9
    Sorry, what I meant by reliable is that they are synced up and the server one is always behind the client one, in a way which would allow the server's ticks to be used to simulate the game slightly in the past from the client.
     
  4. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,892
    That is the only way it can work in server-client networking due to latency.
     
  5. RikuTheFuffs-U

    RikuTheFuffs-U

    Unity Technologies

    Joined:
    Feb 20, 2020
    Posts:
    440
    Hi @duckburger , I asked this to the NGO team to be sure, and this is the answer I've got:

    "See it this way: On the client, you should see the local time ahead(later) of the server time.

    On the server, you should see the local time equal to the server time. (yeah, probably obvious)

    So, this “reliability” description holds.

    But this is all moot, because whenever you receive a NetworkVariable update or an RPC, you don’t get an indication of when it was emitted by the other side (what was the local time when the event happened).

    You can guess it, but this hard factual information is not provided to you by the SDK.

    Especially, if you have multiple clients, you would need two times in the past:
    • when the other client initiated something (a movement, key press, collision, whatever)
    • when it was relayed/authentifed by the server "
    Does this help?
     
  6. duckburger

    duckburger

    Joined:
    Dec 7, 2016
    Posts:
    9
    Sorry, I'm not sure I understand the last part about the indication of when a command was emitter/simulated. Wouldn't that come from the tick number that I will be including in the packet? I guess I could also include the delta time for the command, but not sure that would work with several clients present all with their times if the server simulates everyone at once.
     
  7. lucasthier2015

    lucasthier2015

    Joined:
    Sep 1, 2022
    Posts:
    11
    Server is slightly behind client, the problem is that when sending a ServerRPC the function reaches the server "late" when the tick has already happened. To fix this you need to make use the properties LocalBufferSec and ServerBufferSec. and implement some kind of "system" to constantly change this values in order to keep the server tick enough behind so that the RPC will arrive before the tick hits but not too much to cause latency problems.

    If you want a faster(maybe temporal solution), the lazy/easy way would be to set the LocalBufferSec to something like 1 (this number will change depending on the network conditions). a very high number will cause more latency and a very lower number will cause the rpc to reach the server too late. This means you want to keep it as low as posible to reduce latency but not too much.
     
  8. lucasthier2015

    lucasthier2015

    Joined:
    Sep 1, 2022
    Posts:
    11
    The "system" I use is basicly to send a Server RPC with the client Tick and compare it to the current server tick when it reaches the server if it has already happened(it is to late) increase the BufferSec and if it is too early then reduce it.
    Example code:

    Code (CSharp):
    1.         [ServerRpc(Delivery = RpcDelivery.Unreliable)]
    2.         public void SyncCheck(int TickAtSend)
    3.         {
    4.             if(TickAtSend <= CurrentTick){
    5.                 NetworkManager.NetworkTimeSystem.LocalBufferSec += 0.001
    6.             }
    7.             else if(TickAtSend > (CurrentTick + 2))
    8.                 {
    9.                     NetworkManager.NetworkTimeSystem.LocalBufferSec -= 0.001;
    10.                 }
    11.         }