diff --git a/Lidgren.Network/Lidgren.Network.csproj b/Lidgren.Network/Lidgren.Network.csproj index c153175..8d244c3 100644 --- a/Lidgren.Network/Lidgren.Network.csproj +++ b/Lidgren.Network/Lidgren.Network.csproj @@ -16,7 +16,7 @@ true full - true + false bin\Debug\ DEBUG;TRACE prompt diff --git a/Lidgren.Network/NetConnection.Reliability.cs b/Lidgren.Network/NetConnection.Reliability.cs index 6d00c91..3ffd783 100644 --- a/Lidgren.Network/NetConnection.Reliability.cs +++ b/Lidgren.Network/NetConnection.Reliability.cs @@ -29,6 +29,7 @@ namespace Lidgren.Network private ushort[] m_lastReceivedSequenced; internal readonly Dictionary[] m_storedMessages = new Dictionary[NetConstants.NumReliableChannels]; + internal readonly Dictionary[] m_inverseStored = new Dictionary[NetConstants.NumReliableChannels]; internal readonly NetBitVector m_storedMessagesNotEmpty = new NetBitVector(NetConstants.NumReliableChannels); private readonly ushort[] m_nextExpectedReliableSequence = new ushort[NetConstants.NumReliableChannels]; @@ -50,6 +51,18 @@ namespace Lidgren.Network return retval; } + public int GetWithheldMessagesCount() + { + int retval = 0; + for (int i = 0; i < m_withheldMessages.Length; i++) + { + var list = m_withheldMessages[i]; + if (list != null) + retval += list.Count; + } + return retval; + } + private void InitializeReliability() { int num = ((int)NetMessageType.UserReliableOrdered + NetConstants.NetChannelsPerDeliveryMethod) - (int)NetMessageType.UserSequenced; @@ -91,22 +104,50 @@ namespace Lidgren.Network { m_owner.VerifyNetworkThread(); - ushort seqNr = GetSendSequenceNumber(msg.m_type); + int seqNr = -1; int reliableSlot = (int)msg.m_type - (int)NetMessageType.UserReliableUnordered; - Dictionary slotDict = m_storedMessages[reliableSlot]; + Dictionary invSlotDict = m_inverseStored[reliableSlot]; if (slotDict == null) { slotDict = new Dictionary(); m_storedMessages[reliableSlot] = slotDict; + + invSlotDict = new Dictionary(); + m_inverseStored[reliableSlot] = invSlotDict; + + // (cannot be a resend here) + } + else + { + // we assume there's a invSlotDict if there's a slotDict + // is it a resend? if so, return the old sequence number + ushort oldSeqNr; + if (invSlotDict.TryGetValue(msg, out oldSeqNr)) + seqNr = oldSeqNr; } - Interlocked.Increment(ref msg.m_inQueueCount); - slotDict.Add(seqNr, msg); + if (seqNr != -1) + { + // resend! + // m_owner.LogDebug("Resending " + msg.m_type + "|" + seqNr); + m_statistics.MessageResent(); + } + else + { + // first send + seqNr = GetSendSequenceNumber(msg.m_type); - if (slotDict.Count > 0) - m_storedMessagesNotEmpty.Set(reliableSlot, true); + //m_owner.LogDebug("Sending " + msg.m_type + "|" + seqNr); + + Interlocked.Increment(ref msg.m_inQueueCount); + slotDict.Add((ushort)seqNr, msg); + invSlotDict.Add(msg, (ushort)seqNr); + + if (slotDict.Count > 0) + m_storedMessagesNotEmpty.Set(reliableSlot, true); + } // schedule next resend int numSends = msg.m_numSends; @@ -114,7 +155,7 @@ namespace Lidgren.Network float[] multiplers = m_peerConfiguration.m_resendRTTMultiplier; msg.m_nextResendTime = now + baseTimes[numSends] + (m_averageRoundtripTime * multiplers[numSends]); - return seqNr; + return (ushort)seqNr; } private void Resend(double now, ushort seqNr, NetOutgoingMessage msg) @@ -128,14 +169,14 @@ namespace Lidgren.Network // no more resends! We failed! int reliableSlot = (int)msg.m_type - (int)NetMessageType.UserReliableUnordered; m_storedMessages[reliableSlot].Remove(seqNr); - m_owner.LogWarning("Failed to deliver reliable message " + msg); + m_owner.LogWarning("Failed to deliver reliable message " + msg + " (seqNr " + seqNr + ")"); Disconnect("Failed to deliver reliable message!"); return; // bye } - m_owner.LogVerbose("Resending " + msg); + m_owner.LogVerbose("Resending " + msg + " (seqNr " + seqNr + ")"); Interlocked.Increment(ref msg.m_inQueueCount); m_unsentMessages.EnqueueFirst(msg); @@ -160,7 +201,7 @@ namespace Lidgren.Network { ushort seqNr = (ushort)(buffer[ptr++] | (buffer[ptr++] << 8)); NetMessageType tp = (NetMessageType)buffer[ptr++]; - // m_owner.LogDebug("Got ack for " + tp + " " + seqNr); + //m_owner.LogDebug("Got ack for " + tp + "|" + seqNr); // remove stored message int reliableSlot = (int)tp - (int)NetMessageType.UserReliableUnordered; @@ -175,6 +216,8 @@ namespace Lidgren.Network { // found! dict.Remove(seqNr); + m_inverseStored[reliableSlot].Remove(om); + Interlocked.Decrement(ref om.m_inQueueCount); NetException.Assert(om.m_lastSentTime != 0); diff --git a/Lidgren.Network/NetConnection.cs b/Lidgren.Network/NetConnection.cs index a377624..e4a642d 100644 --- a/Lidgren.Network/NetConnection.cs +++ b/Lidgren.Network/NetConnection.cs @@ -316,7 +316,7 @@ namespace Lidgren.Network { // Expected sequence number AcceptMessage(mtp, isFragment, channelSequenceNumber, ptr, payloadLengthBits); - + ExpectedReliableSequenceArrived(reliableSlot); return; } diff --git a/Lidgren.Network/NetConnectionStatistics.cs b/Lidgren.Network/NetConnectionStatistics.cs index 83f74c9..76b363b 100644 --- a/Lidgren.Network/NetConnectionStatistics.cs +++ b/Lidgren.Network/NetConnectionStatistics.cs @@ -36,6 +36,8 @@ namespace Lidgren.Network internal int m_sentBytes; internal int m_receivedBytes; + internal int m_resentMessages; + internal NetConnectionStatistics(NetConnection conn) { m_connection = conn; @@ -86,18 +88,32 @@ namespace Lidgren.Network m_receivedMessages += numMessages; } + [Conditional("DEBUG")] + internal void MessageResent() + { + m_resentMessages++; + } + public override string ToString() { StringBuilder bdr = new StringBuilder(); bdr.AppendLine("Average roundtrip time: " + NetTime.ToReadable(m_connection.m_averageRoundtripTime)); bdr.AppendLine("Sent " + m_sentBytes + " bytes in " + m_sentMessages + " messages in " + m_sentPackets + " packets"); bdr.AppendLine("Received " + m_receivedBytes + " bytes in " + m_receivedMessages + " messages in " + m_receivedPackets + " packets"); + + if (m_resentMessages > 0) + bdr.AppendLine("Resent messages: " + m_resentMessages); + int numUnsent = m_connection.m_unsentMessages.Count; if (numUnsent > 0) bdr.AppendLine("Unsent messages: " + numUnsent); int numStored = m_connection.GetStoredMessagesCount(); if (numStored > 0) bdr.AppendLine("Stored messages: " + numStored); + int numWithheld = m_connection.GetWithheldMessagesCount(); + if (numWithheld > 0) + bdr.AppendLine("Withheld messages: " + numWithheld); + return bdr.ToString(); } } diff --git a/Lidgren.Network/NetPeer.LatencySimulation.cs b/Lidgren.Network/NetPeer.LatencySimulation.cs index 0514fe7..0828742 100644 --- a/Lidgren.Network/NetPeer.LatencySimulation.cs +++ b/Lidgren.Network/NetPeer.LatencySimulation.cs @@ -45,7 +45,7 @@ namespace Lidgren.Network { if (NetRandom.Instance.Chance(m_configuration.m_loss)) { - LogVerbose("Sending packet " + numBytes + " bytes - SIMULATED LOST!"); + //LogVerbose("Sending packet " + numBytes + " bytes - SIMULATED LOST!"); return; // packet "lost" } } @@ -58,7 +58,7 @@ namespace Lidgren.Network if (m == 0.0f && r == 0.0f) { // no latency simulation - LogVerbose("Sending packet " + numBytes + " bytes"); + //LogVerbose("Sending packet " + numBytes + " bytes"); ActuallySendPacket(m_sendBuffer, numBytes, target); return; } @@ -82,7 +82,7 @@ namespace Lidgren.Network m_delayedPackets.Add(p); } - LogVerbose("Sending packet " + numBytes + " bytes - delayed " + NetTime.ToReadable(delay)); + // LogVerbose("Sending packet " + numBytes + " bytes - delayed " + NetTime.ToReadable(delay)); } private void SendDelayedPackets() diff --git a/Lidgren.Network/NetQueue.cs b/Lidgren.Network/NetQueue.cs index 295ec5a..c2c0598 100644 --- a/Lidgren.Network/NetQueue.cs +++ b/Lidgren.Network/NetQueue.cs @@ -23,7 +23,7 @@ using System.Diagnostics; namespace Lidgren.Network { /// - /// Thread safe queue with TryDequeue() + /// Thread safe (blocking) queue with TryDequeue() and EnqueueFirst() /// [DebuggerDisplay("Count={m_size}")] public sealed class NetQueue @@ -98,38 +98,34 @@ namespace Lidgren.Network } } + // must be called from within a lock(m_lock) ! private void SetCapacity(int newCapacity) { if (m_size == 0) { - lock (m_lock) + if (m_size == 0) { - if (m_size == 0) - { - m_items = new T[newCapacity]; - m_head = 0; - return; - } + m_items = new T[newCapacity]; + m_head = 0; + return; } } T[] newItems = new T[newCapacity]; - lock (m_lock) + if (m_head + m_size - 1 < m_items.Length) { - if (m_head + m_size - 1 < m_items.Length) - { - Array.Copy(m_items, m_head, newItems, 0, m_size); - } - else - { - Array.Copy(m_items, m_head, newItems, 0, m_items.Length - m_head); - Array.Copy(m_items, 0, newItems, m_items.Length - m_head, (m_size - (m_items.Length - m_head))); - } - - m_items = newItems; - m_head = 0; + Array.Copy(m_items, m_head, newItems, 0, m_size); } + else + { + Array.Copy(m_items, m_head, newItems, 0, m_items.Length - m_head); + Array.Copy(m_items, 0, newItems, m_items.Length - m_head, (m_size - (m_items.Length - m_head))); + } + + m_items = newItems; + m_head = 0; + } /// diff --git a/Samples/DurableClient/Program.cs b/Samples/DurableClient/Program.cs index d931de6..363974d 100644 --- a/Samples/DurableClient/Program.cs +++ b/Samples/DurableClient/Program.cs @@ -84,7 +84,7 @@ namespace DurableClient { double now = NetTime.Now; - float speed = 50.0f; + float speed = 1.0f; float speedMultiplier = 1.0f / speed; diff --git a/Samples/DurableServer/Program.cs b/Samples/DurableServer/Program.cs index c07edc7..febb368 100644 --- a/Samples/DurableServer/Program.cs +++ b/Samples/DurableServer/Program.cs @@ -92,6 +92,7 @@ namespace DurableServer case NetDeliveryMethod.ReliableOrdered: if (nr != m_expectedReliableOrdered[chan]) { + //Display("Expected " + m_expectedReliableOrdered[chan] + ", got " + nr); m_reliableOrderedErrors[chan]++; m_expectedReliableOrdered[chan] = nr + 1; } @@ -108,6 +109,9 @@ namespace DurableServer m_sequencedCorrect[chan]++; m_expectedSequenced[chan] = nr + 1; break; + default: + throw new Exception("Bad NetDeliveryMethod: " + msg.DeliveryMethod); + break; } break; } diff --git a/UnitTests/BitVectorTests.cs b/UnitTests/BitVectorTests.cs index 11a6c0d..d5d20dd 100644 --- a/UnitTests/BitVectorTests.cs +++ b/UnitTests/BitVectorTests.cs @@ -11,6 +11,8 @@ namespace UnitTests for (int i = 0; i < 256; i++) { v.Clear(); + if (i > 42 && i < 65) + v = new NetBitVector(256); if (!v.IsEmpty()) throw new NetException("bit vector fail 1"); @@ -23,12 +25,14 @@ namespace UnitTests if (v.IsEmpty()) throw new NetException("bit vector fail 3"); - int f = v.GetFirstSetIndex(); + if (i != 79 && v.Get(79) == true) + throw new NetException("bit vector fail 4"); + int f = v.GetFirstSetIndex(); if (f != i) throw new NetException("bit vector fail 4"); } - + Console.WriteLine("NetBitVector tests OK"); } } diff --git a/UnitTests/Program.cs b/UnitTests/Program.cs index 84b7595..0225a03 100644 --- a/UnitTests/Program.cs +++ b/UnitTests/Program.cs @@ -28,6 +28,24 @@ namespace UnitTests peer.Shutdown("bye"); + // read all message + NetIncomingMessage inc; + while((inc = peer.ReadMessage()) != null) + { + switch(inc.MessageType) + { + case NetIncomingMessageType.DebugMessage: + case NetIncomingMessageType.VerboseDebugMessage: + case NetIncomingMessageType.WarningMessage: + case NetIncomingMessageType.ErrorMessage: + Console.WriteLine("Peer message: " + inc.ReadString()); + break; + case NetIncomingMessageType.Error: + throw new Exception("Received error message!"); + break; + } + } + Console.ReadKey(); }