I have been going round in circles of how to ultimately synchronize the movement of 20 objects through 60 chosen points each. I had several options the main were
So this is how i came to the conclusion that i needed to have a networked universal time accurate to around 0.1 seconds so that the users would see the same movement. Please if you see this as the wrong approach to this networking please let me know as I very much a beginner to networking.
So far I have tried three methods to get this synced time.
I used System.DateTime
believing that it was an accurate and universal time but found variation beyond a second between devices
I tried to calculate the latency between the two devices so i could calulate and remove the device time variation, by
GetAveragePing(NetworkPlayer player);
but this was old and depreciated as the NetworkPlayer class seemed to be no longer functional and compatibleGetCurrentRtt(int hostId, int connectionId, out byte error);
which returned 0 and again i believe may be depreciatedI tried to access a form of synced network time from a server, by
GetNetworkTimestamp();
which I thought may be what i wantedSo for all of these methods have failed so today I am asking you;
Is there another method for syncing time?
Should one of these methods work, so have I gone wrong, in which case i can give further details on my issues and code used?
Is my approach to networking totally wrong, or at least mostly wrong and how do you suggest i achieve my desired goal?
Thank you very much for reading this I hope it is detailed and still clear and if i can help you advance your understanding of my question i will be very happy to assist. Thanks for any answers / enlightening comments.
Code for Networked Time
Script A (Gets Network Time)
using UnityEngine;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using UnityEngine.UI;
public class GetNetworkTime : MonoBehaviour {
public static System.DateTime NetworkTime()
{
//default Windows time server
const string ntpServer = "time.windows.com";
// NTP message size - 16 bytes of the digest (RFC 2030)
var ntpData = new byte[48];
//Setting the Leap Indicator, Version Number and Mode values
ntpData[0] = 0x1B; //LI = 0 (no warning), VN = 3 (IPv4 only), Mode = 3 (Client Mode)
var addresses = Dns.GetHostEntry(ntpServer).AddressList;
//The UDP port number assigned to NTP is 123
var ipEndPoint = new IPEndPoint(addresses[0], 123);
//NTP uses UDP
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.Connect(ipEndPoint);
//Stops code hang if NTP is blocked
socket.ReceiveTimeout = 3000;
socket.Send(ntpData);
socket.Receive(ntpData);
socket.Close();
//Offset to get to the "Transmit Timestamp" field (time at which the reply
//departed the server for the client, in 64-bit timestamp format."
const byte serverReplyTime = 40;
//Get the seconds part
ulong intPart = System.BitConverter.ToUInt32(ntpData, serverReplyTime);
//Get the seconds fraction
ulong fractPart = System.BitConverter.ToUInt32(ntpData, serverReplyTime + 4);
//Convert From big-endian to little-endian
intPart = SwapEndianness(intPart);
fractPart = SwapEndianness(fractPart);
var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);
//**UTC** time
var networkDateTime = (new System.DateTime(1900, 1, 1, 0, 0, 0, System.DateTimeKind.Utc)).AddMilliseconds((long)milliseconds);
//return networkDateTime.ToLocalTime();
return networkDateTime;
}
// stackoverflow.com/a/3294698/162671
static uint SwapEndianness(ulong x)
{
return (uint)(((x & 0x000000ff) << 24) +
((x & 0x0000ff00) << 8) +
((x & 0x00ff0000) >> 8) +
((x & 0xff000000) >> 24));
}
}
Script B (Difference Calculator and Time Logger)
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
using UnityEngine.UI;
public class SyncTime2 : NetworkBehaviour {
public float serverTimeDif;
public float clientTimeDif;
GetNetworkTime GetNetworkTime;
GameObject time;
Text TimeLog;
// Use this for initialization
void Start () {
GetNetworkTime = GetComponent<GetNetworkTime>();
time = GameObject.Find("time");
TimeLog = time.GetComponent<Text>();
if (isServer)
{
serverTimeDif = (float)System.DateTime.UtcNow.TimeOfDay.TotalSeconds - (float) GetNetworkTime.NetworkTime().TimeOfDay.TotalSeconds;
StartCoroutine("DisplayTime", serverTimeDif);
}
else
{
clientTimeDif = (float)System.DateTime.UtcNow.TimeOfDay.TotalSeconds - (float)GetNetworkTime.NetworkTime().TimeOfDay.TotalSeconds;
StartCoroutine("DisplayTime", clientTimeDif);
}
}
IEnumerator DisplayTime (float TimeDif)
{
for (;;)
{
TimeLog.text = "" + ((float)System.DateTime.UtcNow.TimeOfDay.TotalSeconds + TimeDif);
// Log time so i can see if it is different on different devices
yield return new WaitForSeconds(0.01f);
}
}
}
Hmmmff... Seems simply adding the time difference rather than minus-ing it works and synchronizes the time, so rather than
TimeLog.text = "" + ((float)System.DateTime.UtcNow.TimeOfDay.TotalSeconds - TimeDif);
I should use
TimeLog.text = "" - ((float)System.DateTime.UtcNow.TimeOfDay.TotalSeconds + TimeDif);
If anyone could confirm that this is/isn't the correct method of networking I would deem that an answer
User contributions licensed under CC BY-SA 3.0