Network Time - TextGuySemicolon/VPPMultiplayer GitHub Wiki

Overview

NetworkTime is reponsible to handle calculation of latency, ping and server time, client will communicate to the server to calculate a server time offset based on the calculated ping/latency.

NetworkTime

The implementation of NetworkTime is split into 2 scripts called ServerNetworkTime and ClientNetworkTime.

Ping/Latency

In the ClientNetworkTime, we will send the client time to the server. We will send this packet every few seconds to the server we're connecting to.

    public class UpdateTimePacket
    {
        public float client_time; //Time.time on the client
    }

In the ServerNetworkTime, we'll register a callback for when the "GameServer" receive "UpdateTimePacket", we register our callback by subscribing to the "NetPacketProcessor" used in "GameServer".

    private void InitCallbacks()
    {
        GameServer.netPacketProcessor.SubscribeReusable<UpdateTimePacket, NetPeer>(OnUpdateTimeReceived);
    }

In the "OnUpdateTimeReceived" callback, we will send back the "client_time" we got from the "UpdateTimePacket" we received, and the server time. Then the client can do the calculation of ping/latency based on the "client_time".

    public class UpdateTimeResponsePacket
    {
        public float client_time; //the received UpdateTimePacket.client_time
        public float server_time; //Time.time on the server
    }

To Calculate Ping/Latency

the time taken for sending a packet from client to server to client, will be the "ping", the "latency" is the time taken for one way, which we is half of the value of "ping".

    //callback for when we receive"UpdateTimeResponsePacket" on the client.
    public static void UpdateTimeResponse(UpdateTimeResponsePacket _packet)
    {
        var _ping = Time.time - _packet.client_time;
        var _latency = _ping / 2f;
    }

Finally we can use this function to get the server time without worrying about latency affecting the time accuracy.

    public static float GetServerTime()
    {
        return Time.time - serverTimeOffset;
    }

Server Time

time is key,when it comes to calculation or interpolation of movements in the multiplayer space, there might be latency issue when the clients get the server time from the server, in order to make the server time more accurate, we have to calculate the offset time considering the latency on each client.

    private void OnUpdateTimeResponse(UpdateTimeResponsePacket _packet)
    {
        ping = Time.time - _packet.client_time;
        latency = ping / 2f;
        serverTime = _packet.server_time + latency;
        serverTimeOffset = Time.time - serverTime;
    }

a latency is added to the server time we received from "UpdateTimeResponsePacket", in order to get the actual server time by the time we received the packet. Then we will calculate a offset between client time and server time.

Then we will have the "GetServerTime()" that we can use when calculating network logic that is time-based. (ie, vehicle movement interpolation, etc...)

    public static float GetServerTime()
    {
        return Time.time - serverTimeOffset;
    }

Server Offset Interpolation

To prevent skipping server time when the latency changed, we used a simple interpolation to update the server offset time, instead of setting the server time offset directly, we update it gradually in an update method.

    //this is called in the "Update()" method.
    private void SmoothServerTime()
    {
        //this speed is experimental
        float _speed = Time.deltaTime * SERVER_TIME_SMOOTH_CORRECTION_SPEED;
        serverTimeOffset = Mathf.Lerp(serverTimeOffset, targetServerTimeOffset, _speed);
    }