Hello, put this script at the player prefab. Then you can use it by: NetworkTimeManager.GetServerTime(); on both client and server. I also suggest to add a boolean which would allow to access to the Instance only after the time is synced for the first time. Cheers.
/*
-------------------------------------------------------
Developer: Alexander - twitter.com/wobes_1
Date: 28/10/2017 02:38
-------------------------------------------------------
*/
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
namespace Networking.Management
{
public class NetworkTimeManager : NetworkBehaviour
{
public static NetworkTimeManager Instance;
private int startTime;
private int receivedTime;
public override void OnStartLocalPlayer()
{
Instance = this;
}
private void Start()
{
if (isLocalPlayer)
StartCoroutine(RequestServerTime());
}
private IEnumerator RequestServerTime()
{
while (true)
{
CmdRequestServerTime();
yield return new WaitForSeconds(1);
}
}
[Command]
private void CmdRequestServerTime()
{
TargetRpcNetworkTimestamp(connectionToClient, NetworkTransport.GetNetworkTimestamp());
}
[TargetRpc]
private void TargetRpcNetworkTimestamp(NetworkConnection conn, int timestamp)
{
receivedTime = NetworkTransport.GetNetworkTimestamp();
int networkTimestampDelayMS = 0;
if (isServer)
{
networkTimestampDelayMS = 0;
}
else
{
byte error;
networkTimestampDelayMS = NetworkTransport.GetRemoteDelayTimeMS(
NetworkManager.singleton.client.connection.hostId,
NetworkManager.singleton.client.connection.connectionId,
timestamp,
out error);
}
startTime = timestamp + networkTimestampDelayMS;
}
public static double GetServerTime()
{
if (NetworkClient.active)
{
return (Instance.startTime + (NetworkTransport.GetNetworkTimestamp() - Instance.receivedTime)) / 1000.0;
}
else if (NetworkServer.active)
{
return NetworkTransport.GetNetworkTimestamp() / 1000.0;
}
else
{
return 0;
}
}
public override int GetNetworkChannel()
{
return Channels.DefaultUnreliable;
}
}
}
Result (In Seconds) the difference is 1-3 ms because of the OnGUI() timing:
EDIT: Test results of sending a command in order to check the time, for example for shooting in order to know when exactly the client shot.
Snip for testing purpose, hit the Space bar on the client and take a look into the server debug log:
private void Update()
{
if (isLocalPlayer)
{
if (Input.GetKeyDown(KeyCode.Space))
{
CmdCheckTime(GetServerTime(), NetworkTransport.GetNetworkTimestamp());
}
}
}
[Command]
private void CmdCheckTime(double v, int timestamp)
{
Debug.Log("Client command time: " + v.ToString("F4"));
byte error;
int networkTimestampDelayMS = NetworkTransport.GetRemoteDelayTimeMS(
connectionToClient.hostId,
connectionToClient.connectionId,
timestamp,
out error);
int time = NetworkTransport.GetNetworkTimestamp() - networkTimestampDelayMS;
double serverTime = time / 1000.0;
Debug.Log("Server rewind time: " + serverTime.ToString("F4") + " Delay: " + networkTimestampDelayMS + "ms");
Debug.LogError("Current server time: " + GetServerTime().ToString("F4"));
}