Hi there, any ideas how to proper get Network.time on UNET? This is what I got but it's not accurate. P.S Modified code from that post: https://forum.unity3d.com/threads/how-to-sync-network-time.395809/ Spoiler: Code Code (CSharp): /* ------------------------------------------------------- Developer: Alexander - twitter.com/wobes_1 Date: 10/08/2017 21:15 ------------------------------------------------------- */ using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Networking; public class NetworkedPlayer : NetworkBehaviour { public bool isNetworkTimeSynced = false; // timestamp received from server private float networkTime; // server to client delay private int networkTimestampDelayMS; // when did we receive timestamp from server private float timeReceived; protected virtual void Start() { if (isLocalPlayer) { CmdRequestTime(); } } [Server] private void Update() { if (Input.GetKeyDown(KeyCode.Space)) { int timestamp = NetworkTransport.GetNetworkTimestamp(); TargetRpcCheck(connectionToClient, Time.time, timestamp); } } [TargetRpc] void TargetRpcCheck(NetworkConnection conn, float time, int timestamp) { byte error; var delay = NetworkTransport.GetRemoteDelayTimeMS( NetworkManager.singleton.client.connection.hostId, NetworkManager.singleton.client.connection.connectionId, timestamp, out error); Debug.Log(delay); float actualTime = time + (delay / 1000f); Debug.Log("Server time " + actualTime); Debug.Log("Client time " + GetServerTime()); } [Command] private void CmdRequestTime() { int timestamp = NetworkTransport.GetNetworkTimestamp(); RpcNetworkTimestamp(Time.time, timestamp); } [ClientRpc] private void RpcNetworkTimestamp(float time, int timestamp) { isNetworkTimeSynced = true; networkTime = time; timeReceived = Time.time; // if client is a host, assume that there is 0 delay if (isServer) { networkTimestampDelayMS = 0; } else { byte error; networkTimestampDelayMS = NetworkTransport.GetRemoteDelayTimeMS( NetworkManager.singleton.client.connection.hostId, NetworkManager.singleton.client.connection.connectionId, timestamp, out error); } } public float GetServerTime() { return networkTime + (networkTimestampDelayMS / 1000f) + (Time.time - timeReceived); } }
Update: possible reason is NetworkTransport.GetRemoteDelayTimeMS() which is returned strange results. Code (CSharp): /* ------------------------------------------------------- Developer: Alexander - twitter.com/wobes_1 Date: 10/08/2017 21:15 ------------------------------------------------------- */ using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Networking; public class NetworkedPlayer : NetworkBehaviour { public const short SimpleMessageId = MsgType.Highest + 1; public class SimpleMessage : MessageBase { public int timestamp; } public override void OnStartLocalPlayer() { NetworkManager.singleton.client.RegisterHandler(SimpleMessageId, OnMessageReceived); } [ServerCallback] private void Update() { if (Input.GetKeyDown(KeyCode.Space)) { SimpleMessage msg = new SimpleMessage(); msg.timestamp = NetworkTransport.GetNetworkTimestamp(); connectionToClient.Send(SimpleMessageId, msg); } } private void OnMessageReceived(NetworkMessage netMsg) { var msg = netMsg.ReadMessage<SimpleMessage>(); byte error; Debug.Log(NetworkTransport.GetRemoteDelayTimeMS(netMsg.conn.hostId, netMsg.conn.connectionId, msg.timestamp, out error).ToString() + " MS Delay"); } } 0 ms local network 100 ms NetworkSimulator
Update: tested on both Unity 5.6 and 2017.1, still the same results. I think I'm just doing something stupid)
Well, this should be correct. Here is why; When you call GetTimestamp. You create a timstamp AT THAT VERY MOMENT. When you then call GetRemoteMs. You calculate the difference AT THAT VERY MOMENT. This means that when you are totally local. You still have the NetworkTransport buffer. So if you are local player. It takes about 20ms for the packet to be sent and processed after the GetTimestamp. This makes sense due to the MinSendInterval being 0.1 by default. And there also some time for the reciever to actually invoke the callback etc. Basically, the timestamp stuff doesn't interact with the Network Library AFAIK. It's more of a utility method. Here is probably the easiest way to solve it that I can think of: "On Client connect. Send them a message with the servers Time.time and a timestamp. Then the clients will set their networkTime to the serversTime + the delay when that is recieved. That way every client has the servers Time which can be refered to as NetworkTime. They just have to increase it with Time.DeltaTime every frame. But it really depends on the problem you want to solve. For time sync, this would work great I think"
Well, once the time is synced. If you increase it with Time.detlaTime. it will go up by 1 every second. Which is what it does on the server automatically.
yeah but should I it increased in Update function? I guess yes, so that where is de-synchronization happens.
I would grab the server time and delay and then calculate an offset to the machine's local time. Then write a server time method that just applies that offset to local time to return the current server time. Then there would be no need to add Time.deltaTime to the pulled down server time on every update.
For example: Server time is 5000ms, Client join after the main menu, so Time.time now is more than 0ms, you should take into account the current received Time too. so Time.time - timeReceived would return you the actual time since you joined the server. Code (CSharp): return networkTime + (networkTimestampDelayMS / 1000f) + (Time.time - timeReceived); The current code works but it's not accurate, anyway I abandoned my idea, so now I'm currently working only with NetworkTransport.GetNetworkTimestamp();