-
Notifications
You must be signed in to change notification settings - Fork 1
/
NetworkClock.cs
172 lines (135 loc) · 5.37 KB
/
NetworkClock.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
namespace SavageCodes.Networking.ClientSidePrediction
{
public class NetworkClock : NetworkBehaviour
{
[Header("Network Clock Settings")] [SerializeField]
private bool _useAverageLatency;
[SerializeField] private int _latencyBufferSize = 4;
[SerializeField] private bool _useAverageTimeDelta;
[SerializeField] private int _timeDeltaBufferSize = 4;
[SerializeField] private bool _showDebugClock = true;
private int _latency;
private int _averageLatency;
private int _averageTimeDelta;
private int _roundTripTime;
private int _timeDelta;
private Queue<int> _latencyBuffer;
private Queue<int> _timeDeltaBuffer;
private short _timeReceivedFromClientID = 2002;
private short _timeReceivedFromServerID = 2003;
#region Getters
public int Latency => _useAverageLatency ? _averageLatency : _latency;
public int RoundTripTime => _roundTripTime;
public int TimeDelta => _useAverageTimeDelta ? _averageTimeDelta : _timeDelta;
public double CurrentTime =>
((isServer ? DateTime.UtcNow : GetSyncedTime()) - new DateTime(1970, 1, 1, 0, 0, 0))
.TotalMilliseconds;
public DateTime GetSyncedTime()
{
DateTime dateNow = DateTime.UtcNow;
return dateNow.AddMilliseconds(_timeDelta).ToLocalTime();
}
#endregion
void Start()
{
_latencyBuffer = new Queue<int>();
_timeDeltaBuffer = new Queue<int>();
_timeReceivedFromClientID += Convert.ToInt16(netId.Value);
_timeReceivedFromServerID += Convert.ToInt16(netId.Value);
if (isLocalPlayer)
{
StartCoroutine(SendTimeStamp());
}
if (isServer)
{
NetworkServer.RegisterHandler(_timeReceivedFromClientID, OnTimeReceivedFromClient);
}
else
{
NetworkManager.singleton.client.RegisterHandler(_timeReceivedFromServerID, OnTimeReceivedFromServer);
}
}
void OnTimeReceivedFromClient(NetworkMessage netMsg)
{
var timeMessage = netMsg.ReadMessage<TimeMessage>();
timeMessage.serverTimeStamp =
(long) (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalMilliseconds;
NetworkServer.SendToClientOfPlayer(gameObject, _timeReceivedFromServerID, timeMessage);
}
void OnTimeReceivedFromServer(NetworkMessage netMsg)
{
var timeMessage = netMsg.ReadMessage<TimeMessage>();
CalculateTimeDelta(timeMessage);
CalculateAverage(ref _latencyBuffer, _latencyBufferSize, _latency, out _averageLatency);
CalculateAverage(ref _timeDeltaBuffer, _timeDeltaBufferSize, _timeDelta, out _averageTimeDelta);
}
IEnumerator SendTimeStamp()
{
while (true)
{
connectionToServer.Send(_timeReceivedFromClientID, CreateTimePacket());
yield return new WaitForSeconds(5f);
}
}
TimeMessage CreateTimePacket()
{
var timePacket = new TimeMessage
{
clientTimeStamp = (long) (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalMilliseconds
};
return timePacket;
}
void CalculateTimeDelta(TimeMessage timeMessage)
{
_roundTripTime = (int) ((long) (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalMilliseconds -
timeMessage.clientTimeStamp);
_latency = _roundTripTime / 2;
int serverDelta = (int) (timeMessage.serverTimeStamp -
(long) (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalMilliseconds);
_timeDelta = serverDelta + _latency;
}
void CalculateAverage(ref Queue<int> buffer, int bufferSize, int value, out int average)
{
buffer.Enqueue(value);
if (buffer.Count > bufferSize)
{
buffer.Dequeue();
}
var accumulator = 0;
foreach (var val in buffer)
{
accumulator += val;
}
average = accumulator /
(bufferSize < buffer.Count ? buffer.Count : bufferSize);
}
void OnGUI()
{
if (!_showDebugClock) return;
if (isServer)
{
GUI.Label(new Rect(10, 250, 400, 30), "Server Time:" + System.DateTime.Now.TimeOfDay);
return;
}
if (!isLocalPlayer)
return;
GUI.Label(new Rect(10, 250, 400, 30), "Server Time:" + GetSyncedTime().TimeOfDay);
GUI.Label(new Rect(10, 270, 400, 30), "Latency:" + Latency.ToString() + "ms");
GUI.Label(new Rect(10, 290, 400, 30), "Time Delta:" + TimeDelta.ToString() + "ms");
}
private void OnDestroy()
{
StopAllCoroutines();
}
}
public class TimeMessage : MessageBase
{
public long clientTimeStamp;
public long serverTimeStamp;
}
}