diff --git a/Lidgren.Network/NetConnection.Handshake.cs b/Lidgren.Network/NetConnection.Handshake.cs
index a9fee3e..612c027 100644
--- a/Lidgren.Network/NetConnection.Handshake.cs
+++ b/Lidgren.Network/NetConnection.Handshake.cs
@@ -183,7 +183,7 @@ namespace Lidgren.Network
m_peer.m_handshakes.Remove(m_remoteEndpoint); // TODO: make this more thread safe? we're on user thread
}
- internal void ReceivedHandshake(NetMessageType tp, int ptr, int payloadLength)
+ internal void ReceivedHandshake(double now, NetMessageType tp, int ptr, int payloadLength)
{
m_peer.VerifyNetworkThread();
@@ -211,6 +211,7 @@ namespace Lidgren.Network
{
// ok, let's not add connection just yet
NetIncomingMessage appMsg = m_peer.CreateIncomingMessage(NetIncomingMessageType.ConnectionApproval, (m_remoteHailMessage == null ? 0 : m_remoteHailMessage.LengthBytes));
+ appMsg.m_receiveTime = now;
appMsg.m_senderConnection = this;
appMsg.m_senderEndpoint = this.m_remoteEndpoint;
if (m_remoteHailMessage != null)
diff --git a/Lidgren.Network/NetConnection.Latency.cs b/Lidgren.Network/NetConnection.Latency.cs
index f6e9bd2..ca832d4 100644
--- a/Lidgren.Network/NetConnection.Latency.cs
+++ b/Lidgren.Network/NetConnection.Latency.cs
@@ -9,11 +9,19 @@ namespace Lidgren.Network
private float m_averageRoundtripTime;
private float m_timeoutDeadline = float.MaxValue;
+ // local time value + m_remoteTimeOffset = remote time value
+ internal double m_remoteTimeOffset;
+
///
/// Gets the current average roundtrip time in seconds
///
public float AverageRoundtripTime { get { return m_averageRoundtripTime; } }
+ internal double GetLocalTime(double remoteTimeStamp)
+ {
+ return remoteTimeStamp - m_remoteTimeOffset;
+ }
+
internal void InitializePing()
{
// randomize ping sent time (0.25 - 1.0 x ping interval)
@@ -27,11 +35,10 @@ namespace Lidgren.Network
m_peer.VerifyNetworkThread();
m_sentPingNumber++;
- if (m_sentPingNumber >= 256)
- m_sentPingNumber = 0;
+
m_sentPingTime = (float)NetTime.Now;
NetOutgoingMessage om = m_peer.CreateMessage(1);
- om.Write((byte)m_sentPingNumber);
+ om.Write((byte)m_sentPingNumber); // truncating to 0-255
om.m_messageType = NetMessageType.Ping;
int len = om.Encode(m_peer.m_sendBuffer, 0, 0);
@@ -45,20 +52,22 @@ namespace Lidgren.Network
{
m_peer.VerifyNetworkThread();
- NetOutgoingMessage om = m_peer.CreateMessage(1);
+ NetOutgoingMessage om = m_peer.CreateMessage(5);
om.Write((byte)pingNumber);
+ om.Write((float)NetTime.Now); // we should update this value to reflect the exact point in time the packet is SENT
om.m_messageType = NetMessageType.Pong;
int len = om.Encode(m_peer.m_sendBuffer, 0, 0);
bool connectionReset;
+
m_peer.SendPacket(len, m_remoteEndpoint, 1, out connectionReset);
m_statistics.PacketSent(len, 1);
}
- internal void ReceivedPong(float now, int pongNumber)
+ internal void ReceivedPong(float now, int pongNumber, float remoteSendTime)
{
- if (pongNumber != m_sentPingNumber)
+ if ((byte)pongNumber != (byte)m_sentPingNumber)
{
m_peer.LogVerbose("Ping/Pong mismatch; dropped message?");
return;
@@ -69,15 +78,20 @@ namespace Lidgren.Network
float rtt = now - m_sentPingTime;
NetException.Assert(rtt >= 0);
+ double diff = (remoteSendTime + (rtt / 2.0)) - now;
+
if (m_averageRoundtripTime < 0)
{
+ m_remoteTimeOffset = diff;
m_averageRoundtripTime = rtt; // initial estimate
- m_peer.LogDebug("Initiated average roundtrip time to " + NetTime.ToReadable(m_averageRoundtripTime));
+ m_peer.LogDebug("Initiated average roundtrip time to " + NetTime.ToReadable(m_averageRoundtripTime) + " Server time is: " + (now + diff));
}
else
{
m_averageRoundtripTime = (m_averageRoundtripTime * 0.7f) + (float)(rtt * 0.3f);
- m_peer.LogVerbose("Updated average roundtrip time to " + NetTime.ToReadable(m_averageRoundtripTime));
+
+ m_remoteTimeOffset = ((m_remoteTimeOffset * (double)(m_sentPingNumber - 1)) + diff) / (double)m_sentPingNumber;
+ m_peer.LogVerbose("Updated average roundtrip time to " + NetTime.ToReadable(m_averageRoundtripTime) + ", server time to " + (now + m_remoteTimeOffset) + " (ie. diff " + m_remoteTimeOffset + ")");
}
// update resend delay for all channels
@@ -89,7 +103,17 @@ namespace Lidgren.Network
rchan.m_resendDelay = resendDelay;
}
- m_peer.LogVerbose("Timeout deadline pushed to " + m_timeoutDeadline);
+ // m_peer.LogVerbose("Timeout deadline pushed to " + m_timeoutDeadline);
+
+ // notify the application that average rtt changed
+ if (m_peer.m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.ConnectionLatencyUpdated))
+ {
+ NetIncomingMessage update = m_peer.CreateIncomingMessage(NetIncomingMessageType.ConnectionLatencyUpdated, 4);
+ update.m_senderConnection = this;
+ update.m_senderEndpoint = this.m_remoteEndpoint;
+ update.Write(rtt);
+ m_peer.ReleaseMessage(update);
+ }
}
}
}
diff --git a/Lidgren.Network/NetConnection.MTU.cs b/Lidgren.Network/NetConnection.MTU.cs
index 4818a55..28ff6c4 100644
--- a/Lidgren.Network/NetConnection.MTU.cs
+++ b/Lidgren.Network/NetConnection.MTU.cs
@@ -26,7 +26,7 @@ namespace Lidgren.Network
internal void InitExpandMTU(double now)
{
- m_lastSentMTUAttemptTime = now + m_peerConfiguration.m_expandMTUFrequency + 1.0f; // wait a tiny bit before starting to expand mtu
+ m_lastSentMTUAttemptTime = now + m_peerConfiguration.m_expandMTUFrequency + 1.5f + m_averageRoundtripTime; // wait a tiny bit before starting to expand mtu
m_largestSuccessfulMTU = 512;
m_smallestFailedMTU = -1;
m_currentMTU = m_peerConfiguration.MaximumTransmissionUnit;
diff --git a/Lidgren.Network/NetConnection.cs b/Lidgren.Network/NetConnection.cs
index dcffbc2..d5916b1 100644
--- a/Lidgren.Network/NetConnection.cs
+++ b/Lidgren.Network/NetConnection.cs
@@ -138,10 +138,10 @@ namespace Lidgren.Network
{
if (now > m_sentPingTime + m_peer.m_configuration.m_pingInterval)
SendPing();
- }
- // handle expand mtu
- MTUExpansionHeartbeat(now);
+ // handle expand mtu
+ MTUExpansionHeartbeat(now);
+ }
if (m_disconnectRequested)
{
@@ -352,8 +352,10 @@ namespace Lidgren.Network
SendPong(pingNr);
break;
case NetMessageType.Pong:
- int pongNr = m_peer.m_receiveBuffer[ptr++];
- ReceivedPong(now, pongNr);
+ NetIncomingMessage pmsg = m_peer.SetupReadHelperMessage(ptr, payloadLength);
+ int pongNr = pmsg.ReadByte();
+ float remoteSendTime = pmsg.ReadSingle();
+ ReceivedPong(now, pongNr, remoteSendTime);
break;
case NetMessageType.ExpandMTURequest:
SendMTUSuccess(payloadLength);
diff --git a/Lidgren.Network/NetIncomingMessage.Read.cs b/Lidgren.Network/NetIncomingMessage.Read.cs
index d242514..5160b7b 100644
--- a/Lidgren.Network/NetIncomingMessage.Read.cs
+++ b/Lidgren.Network/NetIncomingMessage.Read.cs
@@ -465,6 +465,20 @@ namespace Lidgren.Network
return new IPEndPoint(address, port);
}
+ ///
+ /// Reads a value, in local time comparable to NetTime.Now, written using WriteTime()
+ /// Must have a connected sender
+ ///
+ public double ReadTime(bool highPrecision)
+ {
+ double remoteTime = (highPrecision ? ReadDouble() : (double)ReadSingle());
+
+ if (m_senderConnection == null)
+ throw new NetException("Cannot call ReadTime() on message without a connected sender (ie. unconnected messages)");
+
+ return remoteTime - m_senderConnection.m_remoteTimeOffset;
+ }
+
///
/// Pads data with enough bits to reach a full byte. Decreases cpu usage for subsequent byte writes.
///
diff --git a/Lidgren.Network/NetIncomingMessage.cs b/Lidgren.Network/NetIncomingMessage.cs
index a75f0b3..f10f326 100644
--- a/Lidgren.Network/NetIncomingMessage.cs
+++ b/Lidgren.Network/NetIncomingMessage.cs
@@ -36,6 +36,7 @@ namespace Lidgren.Network
internal int m_sequenceNumber;
internal NetMessageType m_receivedMessageType;
internal bool m_isFragment;
+ internal double m_receiveTime;
///
/// Gets the type of this incoming message
@@ -62,6 +63,11 @@ namespace Lidgren.Network
///
public NetConnection SenderConnection { get { return m_senderConnection; } }
+ ///
+ /// What local time the message was received from the network
+ ///
+ public double ReceiveTime { get { return m_receiveTime; } }
+
///
/// Gets the length of the message payload in bytes
///
diff --git a/Lidgren.Network/NetIncomingMessageType.cs b/Lidgren.Network/NetIncomingMessageType.cs
index 99d0cc5..b05cd56 100644
--- a/Lidgren.Network/NetIncomingMessageType.cs
+++ b/Lidgren.Network/NetIncomingMessageType.cs
@@ -42,5 +42,6 @@ namespace Lidgren.Network
WarningMessage = 1 << 9, // Data (string)
ErrorMessage = 1 << 10, // Data (string)
NatIntroductionSuccess = 1 << 11, // Data (as passed to master server)
+ ConnectionLatencyUpdated = 1 << 12, // Seconds as a Single
}
}
diff --git a/Lidgren.Network/NetOutgoingMessage.Write.cs b/Lidgren.Network/NetOutgoingMessage.Write.cs
index 07a1711..3312dad 100644
--- a/Lidgren.Network/NetOutgoingMessage.Write.cs
+++ b/Lidgren.Network/NetOutgoingMessage.Write.cs
@@ -534,6 +534,17 @@ namespace Lidgren.Network
Write((ushort)endPoint.Port);
}
+ ///
+ /// Writes the local time to a message; readable (and convertable to local time) by the remote host using ReadTime()
+ ///
+ public void WriteTime(double localTime, bool highPrecision)
+ {
+ if (highPrecision)
+ Write(localTime);
+ else
+ Write((float)localTime);
+ }
+
///
/// Pads data with enough bits to reach a full byte. Decreases cpu usage for subsequent byte writes.
///
diff --git a/Lidgren.Network/NetPeer.Fragmentation.cs b/Lidgren.Network/NetPeer.Fragmentation.cs
index 0eed9ab..08027f6 100644
--- a/Lidgren.Network/NetPeer.Fragmentation.cs
+++ b/Lidgren.Network/NetPeer.Fragmentation.cs
@@ -124,7 +124,7 @@ namespace Lidgren.Network
Buffer.BlockCopy(im.m_data, ptr, info.Data, offset, im.LengthBytes - ptr);
int cnt = info.ReceivedChunks.Count();
- //Console.WriteLine("Found fragment #" + chunkNumber + " in group " + group + " offset " + offset + " of total bits " + totalBits + " (total chunks done " + cnt + ")");
+ //LogVerbose("Found fragment #" + chunkNumber + " in group " + group + " offset " + offset + " of total bits " + totalBits + " (total chunks done " + cnt + ")");
LogVerbose("Received fragment " + chunkNumber + " of " + totalNumChunks + " (" + cnt + " chunks received)");
diff --git a/Lidgren.Network/NetPeer.Internal.cs b/Lidgren.Network/NetPeer.Internal.cs
index 983b943..3dd5750 100644
--- a/Lidgren.Network/NetPeer.Internal.cs
+++ b/Lidgren.Network/NetPeer.Internal.cs
@@ -43,9 +43,6 @@ namespace Lidgren.Network
{
NetException.Assert(msg.m_incomingMessageType != NetIncomingMessageType.Error);
- if (msg.MessageType == NetIncomingMessageType.UnconnectedData)
- Console.WriteLine("x");
-
if (msg.m_isFragment)
{
HandleReleasedFragment(msg);
@@ -306,6 +303,7 @@ namespace Lidgren.Network
NetConnection sender = null;
m_connectionLookup.TryGetValue(ipsender, out sender);
+ double receiveTime = NetTime.Now;
//
// parse packet into messages
//
@@ -344,7 +342,7 @@ namespace Lidgren.Network
if (sender != null)
sender.ReceivedLibraryMessage(tp, ptr, payloadByteLength);
else
- ReceivedUnconnectedLibraryMessage(ipsender, tp, ptr, payloadByteLength);
+ ReceivedUnconnectedLibraryMessage(receiveTime, ipsender, tp, ptr, payloadByteLength);
}
else
{
@@ -353,6 +351,7 @@ namespace Lidgren.Network
NetIncomingMessage msg = CreateIncomingMessage(NetIncomingMessageType.Data, payloadByteLength);
msg.m_isFragment = isFragment;
+ msg.m_receiveTime = receiveTime;
msg.m_sequenceNumber = sequenceNumber;
msg.m_receivedMessageType = tp;
msg.m_senderConnection = sender;
@@ -390,12 +389,12 @@ namespace Lidgren.Network
}
}
- private void ReceivedUnconnectedLibraryMessage(IPEndPoint senderEndpoint, NetMessageType tp, int ptr, int payloadByteLength)
+ private void ReceivedUnconnectedLibraryMessage(double now, IPEndPoint senderEndpoint, NetMessageType tp, int ptr, int payloadByteLength)
{
NetConnection shake;
if (m_handshakes.TryGetValue(senderEndpoint, out shake))
{
- shake.ReceivedHandshake(tp, ptr, payloadByteLength);
+ shake.ReceivedHandshake(now, tp, ptr, payloadByteLength);
return;
}
@@ -410,6 +409,7 @@ namespace Lidgren.Network
NetIncomingMessage dm = CreateIncomingMessage(NetIncomingMessageType.DiscoveryRequest, payloadByteLength);
if (payloadByteLength > 0)
Buffer.BlockCopy(m_receiveBuffer, ptr, dm.m_data, 0, payloadByteLength);
+ dm.m_receiveTime = now;
dm.m_bitLength = payloadByteLength * 8;
dm.m_senderEndpoint = senderEndpoint;
ReleaseMessage(dm);
@@ -422,6 +422,7 @@ namespace Lidgren.Network
NetIncomingMessage dr = CreateIncomingMessage(NetIncomingMessageType.DiscoveryResponse, payloadByteLength);
if (payloadByteLength > 0)
Buffer.BlockCopy(m_receiveBuffer, ptr, dr.m_data, 0, payloadByteLength);
+ dr.m_receiveTime = now;
dr.m_bitLength = payloadByteLength * 8;
dr.m_senderEndpoint = senderEndpoint;
ReleaseMessage(dr);
@@ -460,7 +461,7 @@ namespace Lidgren.Network
// Ok, start handshake!
NetConnection conn = new NetConnection(this, senderEndpoint);
m_handshakes.Add(senderEndpoint, conn);
- conn.ReceivedHandshake(tp, ptr, payloadByteLength);
+ conn.ReceivedHandshake(now, tp, ptr, payloadByteLength);
return;
}
diff --git a/Lidgren.Network/NetPeerConfiguration.cs b/Lidgren.Network/NetPeerConfiguration.cs
index 0755f5f..f6748b3 100644
--- a/Lidgren.Network/NetPeerConfiguration.cs
+++ b/Lidgren.Network/NetPeerConfiguration.cs
@@ -67,7 +67,7 @@ namespace Lidgren.Network
//
// default values
//
- m_disabledTypes = NetIncomingMessageType.ConnectionApproval | NetIncomingMessageType.UnconnectedData | NetIncomingMessageType.VerboseDebugMessage;
+ m_disabledTypes = NetIncomingMessageType.ConnectionApproval | NetIncomingMessageType.UnconnectedData | NetIncomingMessageType.VerboseDebugMessage | NetIncomingMessageType.ConnectionLatencyUpdated;
m_networkThreadName = "Lidgren network thread";
m_localAddress = IPAddress.Any;
m_port = 0;