You've already forked lidgren-network-gen3
mirror of
https://github.com/lidgren/lidgren-network-gen3.git
synced 2026-05-06 02:11:06 +09:00
Sequence numbers now stored in dictionary per connection to enable sending the same message reliable ordered message to several connections
This commit is contained in:
@@ -100,9 +100,10 @@ namespace Lidgren.Network
|
||||
}
|
||||
m_owner.LogVerbose("Sending Connect");
|
||||
|
||||
m_owner.SendImmediately(this, om);
|
||||
double now = NetTime.Now;
|
||||
m_owner.SendImmediately(now, this, om);
|
||||
|
||||
m_connectInitationTime = NetTime.Now;
|
||||
m_connectInitationTime = now;
|
||||
SetStatus(NetConnectionStatus.Connecting, "Connecting");
|
||||
|
||||
return;
|
||||
@@ -110,24 +111,28 @@ namespace Lidgren.Network
|
||||
|
||||
internal void SendConnectResponse()
|
||||
{
|
||||
double now = NetTime.Now;
|
||||
|
||||
NetOutgoingMessage reply = m_owner.CreateMessage(4);
|
||||
reply.m_type = NetMessageType.Library;
|
||||
reply.m_libType = NetMessageLibraryType.ConnectResponse;
|
||||
reply.Write((float)NetTime.Now);
|
||||
reply.Write((float)now);
|
||||
|
||||
m_owner.LogVerbose("Sending LibraryConnectResponse");
|
||||
m_owner.SendImmediately(this, reply);
|
||||
m_owner.SendImmediately(now, this, reply);
|
||||
}
|
||||
|
||||
internal void SendConnectionEstablished()
|
||||
{
|
||||
double now = NetTime.Now;
|
||||
|
||||
NetOutgoingMessage ce = m_owner.CreateMessage(4);
|
||||
ce.m_type = NetMessageType.Library;
|
||||
ce.m_libType = NetMessageLibraryType.ConnectionEstablished;
|
||||
ce.Write((float)NetTime.Now);
|
||||
ce.Write((float)now);
|
||||
|
||||
m_owner.LogVerbose("Sending LibraryConnectionEstablished");
|
||||
m_owner.SendImmediately(this, ce);
|
||||
m_owner.SendImmediately(now, this, ce);
|
||||
}
|
||||
|
||||
internal void ExecuteDisconnect(bool sendByeMessage)
|
||||
@@ -160,9 +165,9 @@ namespace Lidgren.Network
|
||||
// release some held memory
|
||||
if (m_storedMessages != null)
|
||||
{
|
||||
foreach (List<NetOutgoingMessage> oml in m_storedMessages)
|
||||
if (oml != null)
|
||||
oml.Clear();
|
||||
foreach (var dict in m_storedMessages)
|
||||
if (dict != null)
|
||||
dict.Clear();
|
||||
}
|
||||
m_acknowledgesToSend.Clear();
|
||||
|
||||
|
||||
@@ -59,15 +59,17 @@ namespace Lidgren.Network
|
||||
|
||||
internal void HandleIncomingPing(byte pingNumber)
|
||||
{
|
||||
double now = NetTime.Now;
|
||||
|
||||
// send pong
|
||||
NetOutgoingMessage pong = m_owner.CreateMessage(1);
|
||||
pong.m_type = NetMessageType.Library;
|
||||
pong.m_libType = NetMessageLibraryType.Pong;
|
||||
pong.Write((byte)pingNumber);
|
||||
pong.Write(NetTime.Now);
|
||||
pong.Write(now);
|
||||
|
||||
// send immediately
|
||||
m_owner.SendImmediately(this, pong);
|
||||
m_owner.SendImmediately(now, this, pong);
|
||||
}
|
||||
|
||||
internal void HandleIncomingPong(double receiveNow, byte pingNumber, double remoteNetTime)
|
||||
@@ -146,7 +148,7 @@ namespace Lidgren.Network
|
||||
ping.m_libType = NetMessageLibraryType.Ping;
|
||||
ping.Write((byte)m_lastSentPingNumber);
|
||||
|
||||
m_owner.SendImmediately(this, ping);
|
||||
m_owner.SendImmediately(now, this, ping);
|
||||
|
||||
m_lastPingSendTime = NetTime.Now; // need exact number
|
||||
m_nextPing = now + m_owner.Configuration.m_pingFrequency;
|
||||
|
||||
@@ -28,8 +28,7 @@ namespace Lidgren.Network
|
||||
private ushort[] m_nextSendSequenceNumber;
|
||||
private ushort[] m_lastReceivedSequenced;
|
||||
|
||||
// TODO: naïve! replace by something better?
|
||||
internal readonly List<NetOutgoingMessage>[] m_storedMessages = new List<NetOutgoingMessage>[NetConstants.NumReliableChannels];
|
||||
internal readonly Dictionary<ushort, NetOutgoingMessage>[] m_storedMessages = new Dictionary<ushort, NetOutgoingMessage>[NetConstants.NumReliableChannels];
|
||||
internal readonly NetBitVector m_storedMessagesNotEmpty = new NetBitVector(NetConstants.NumReliableChannels);
|
||||
|
||||
private readonly ushort[] m_nextExpectedReliableSequence = new ushort[NetConstants.NumReliableChannels];
|
||||
@@ -44,7 +43,7 @@ namespace Lidgren.Network
|
||||
int retval = 0;
|
||||
for (int i = 0; i < m_storedMessages.Length; i++)
|
||||
{
|
||||
List<NetOutgoingMessage> list = m_storedMessages[i];
|
||||
var list = m_storedMessages[i];
|
||||
if (list != null)
|
||||
retval += list.Count;
|
||||
}
|
||||
@@ -87,23 +86,26 @@ namespace Lidgren.Network
|
||||
return false;
|
||||
}
|
||||
|
||||
// called the FIRST time a reliable message is sent
|
||||
private void StoreReliableMessage(double now, NetOutgoingMessage msg)
|
||||
// called by Encode() to retrieve a sequence number and store the message for potential resending
|
||||
internal ushort StoreReliableMessage(double now, NetOutgoingMessage msg)
|
||||
{
|
||||
m_owner.VerifyNetworkThread();
|
||||
|
||||
ushort seqNr = GetSendSequenceNumber(msg.m_type);
|
||||
|
||||
int reliableSlot = (int)msg.m_type - (int)NetMessageType.UserReliableUnordered;
|
||||
|
||||
List<NetOutgoingMessage> list = m_storedMessages[reliableSlot];
|
||||
if (list == null)
|
||||
Dictionary<ushort, NetOutgoingMessage> slotDict = m_storedMessages[reliableSlot];
|
||||
if (slotDict == null)
|
||||
{
|
||||
list = new List<NetOutgoingMessage>();
|
||||
m_storedMessages[reliableSlot] = list;
|
||||
slotDict = new Dictionary<ushort, NetOutgoingMessage>();
|
||||
m_storedMessages[reliableSlot] = slotDict;
|
||||
}
|
||||
Interlocked.Increment(ref msg.m_inQueueCount);
|
||||
list.Add(msg);
|
||||
|
||||
if (list.Count == 1)
|
||||
Interlocked.Increment(ref msg.m_inQueueCount);
|
||||
slotDict.Add(seqNr, msg);
|
||||
|
||||
if (slotDict.Count > 0)
|
||||
m_storedMessagesNotEmpty.Set(reliableSlot, true);
|
||||
|
||||
// schedule next resend
|
||||
@@ -111,9 +113,11 @@ namespace Lidgren.Network
|
||||
float[] baseTimes = m_peerConfiguration.m_resendBaseTime;
|
||||
float[] multiplers = m_peerConfiguration.m_resendRTTMultiplier;
|
||||
msg.m_nextResendTime = now + baseTimes[numSends] + (m_averageRoundtripTime * multiplers[numSends]);
|
||||
|
||||
return seqNr;
|
||||
}
|
||||
|
||||
private void Resend(double now, NetOutgoingMessage msg)
|
||||
private void Resend(double now, ushort seqNr, NetOutgoingMessage msg)
|
||||
{
|
||||
m_owner.VerifyNetworkThread();
|
||||
|
||||
@@ -123,8 +127,7 @@ namespace Lidgren.Network
|
||||
{
|
||||
// no more resends! We failed!
|
||||
int reliableSlot = (int)msg.m_type - (int)NetMessageType.UserReliableUnordered;
|
||||
List<NetOutgoingMessage> list = m_storedMessages[reliableSlot];
|
||||
list.Remove(msg);
|
||||
m_storedMessages[reliableSlot].Remove(seqNr);
|
||||
m_owner.LogWarning("Failed to deliver reliable message " + msg);
|
||||
|
||||
Disconnect("Failed to deliver reliable message!");
|
||||
@@ -162,18 +165,16 @@ namespace Lidgren.Network
|
||||
// remove stored message
|
||||
int reliableSlot = (int)tp - (int)NetMessageType.UserReliableUnordered;
|
||||
|
||||
List<NetOutgoingMessage> list = m_storedMessages[reliableSlot];
|
||||
if (list == null)
|
||||
var dict = m_storedMessages[reliableSlot];
|
||||
if (dict == null)
|
||||
continue;
|
||||
|
||||
// find message
|
||||
for (int a = 0; a < list.Count; a++)
|
||||
{
|
||||
NetOutgoingMessage om = list[a];
|
||||
if (om.m_sequenceNumber == seqNr)
|
||||
NetOutgoingMessage om;
|
||||
if (dict.TryGetValue(seqNr, out om))
|
||||
{
|
||||
// found!
|
||||
list.RemoveAt(a);
|
||||
dict.Remove(seqNr);
|
||||
Interlocked.Decrement(ref om.m_inQueueCount);
|
||||
|
||||
NetException.Assert(om.m_lastSentTime != 0);
|
||||
@@ -183,9 +184,6 @@ namespace Lidgren.Network
|
||||
|
||||
if (om.m_inQueueCount < 1)
|
||||
m_owner.Recycle(om);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: receipt handling
|
||||
|
||||
@@ -148,11 +148,13 @@ namespace Lidgren.Network
|
||||
{
|
||||
if (m_storedMessagesNotEmpty.Get(i))
|
||||
{
|
||||
foreach (NetOutgoingMessage om in m_storedMessages[i])
|
||||
Dictionary<ushort, NetOutgoingMessage> dict = m_storedMessages[i];
|
||||
foreach (ushort seqNr in m_storedMessages[i].Keys)
|
||||
{
|
||||
NetOutgoingMessage om = dict[seqNr];
|
||||
if (now >= om.m_nextResendTime)
|
||||
{
|
||||
Resend(now, om);
|
||||
Resend(now, seqNr, om);
|
||||
break; // need to break out here; collection may have been modified
|
||||
}
|
||||
}
|
||||
@@ -216,15 +218,9 @@ namespace Lidgren.Network
|
||||
// encode message
|
||||
//
|
||||
|
||||
ptr = msg.Encode(buffer, ptr, this);
|
||||
ptr = msg.Encode(now, buffer, ptr, this);
|
||||
numIncludedMessages++;
|
||||
|
||||
if (msg.m_type >= NetMessageType.UserReliableUnordered && msg.m_numSends == 1)
|
||||
{
|
||||
// message is sent for the first time, and is reliable, store for resend
|
||||
StoreReliableMessage(now, msg);
|
||||
}
|
||||
|
||||
// room to piggyback some acks?
|
||||
if (m_acknowledgesToSend.Count > 0)
|
||||
{
|
||||
@@ -612,12 +608,12 @@ namespace Lidgren.Network
|
||||
// shorten resend times
|
||||
for (int i = 0; i < m_storedMessages.Length; i++)
|
||||
{
|
||||
List<NetOutgoingMessage> list = m_storedMessages[i];
|
||||
if (list != null)
|
||||
Dictionary<ushort, NetOutgoingMessage> dict = m_storedMessages[i];
|
||||
if (dict != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (NetOutgoingMessage om in list)
|
||||
foreach (NetOutgoingMessage om in dict.Values)
|
||||
om.m_nextResendTime = (om.m_nextResendTime * 0.8) - 0.05;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
|
||||
@@ -113,6 +113,7 @@ namespace Lidgren.Network
|
||||
{
|
||||
m_bitLength = 0;
|
||||
m_readPosition = 0;
|
||||
m_status = NetIncomingMessageReleaseStatus.NotReleased;
|
||||
m_fragmentationInfo = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ namespace Lidgren.Network
|
||||
|
||||
internal NetMessageType m_type;
|
||||
internal NetMessageLibraryType m_libType;
|
||||
internal ushort m_sequenceNumber;
|
||||
|
||||
internal IPEndPoint m_unconnectedRecipient;
|
||||
|
||||
@@ -99,7 +98,8 @@ namespace Lidgren.Network
|
||||
return ptr;
|
||||
}
|
||||
|
||||
internal int Encode(byte[] buffer, int ptr, NetConnection conn)
|
||||
// encode and store for resending (if conn != null and message is reliable)
|
||||
internal int Encode(double now, byte[] buffer, int ptr, NetConnection conn)
|
||||
{
|
||||
// message type
|
||||
buffer[ptr++] = (byte)((int)m_type | (m_fragmentGroupId == -1 ? 0 : 128));
|
||||
@@ -112,10 +112,15 @@ namespace Lidgren.Network
|
||||
{
|
||||
if (conn == null)
|
||||
throw new NetException("Trying to encode NetMessageType " + m_type + " to unconnected endpoint!");
|
||||
if (m_numSends == 0)
|
||||
m_sequenceNumber = conn.GetSendSequenceNumber(m_type);
|
||||
buffer[ptr++] = (byte)m_sequenceNumber;
|
||||
buffer[ptr++] = (byte)(m_sequenceNumber >> 8);
|
||||
|
||||
ushort seqNr;
|
||||
if (m_type >= NetMessageType.UserReliableUnordered)
|
||||
seqNr = conn.GetSendSequenceNumber(m_type); // "disposable" sequence number
|
||||
else
|
||||
seqNr = conn.StoreReliableMessage(now, this);
|
||||
|
||||
buffer[ptr++] = (byte)seqNr;
|
||||
buffer[ptr++] = (byte)(seqNr >> 8);
|
||||
}
|
||||
|
||||
// payload length
|
||||
@@ -187,8 +192,6 @@ namespace Lidgren.Network
|
||||
bdr.Append('|');
|
||||
bdr.Append(m_libType.ToString());
|
||||
}
|
||||
bdr.Append(" #");
|
||||
bdr.Append(m_sequenceNumber);
|
||||
bdr.Append(" sent ");
|
||||
bdr.Append(m_numSends);
|
||||
bdr.Append(" times]");
|
||||
|
||||
@@ -229,7 +229,7 @@ namespace Lidgren.Network
|
||||
// TODO: use throttling here
|
||||
//
|
||||
|
||||
int ptr = um.Encode(m_sendBuffer, 0, null);
|
||||
int ptr = um.Encode(now, m_sendBuffer, 0, null);
|
||||
|
||||
if (recipient.Address.Equals(IPAddress.Broadcast))
|
||||
{
|
||||
@@ -577,12 +577,12 @@ namespace Lidgren.Network
|
||||
return NetDeliveryMethod.Unreliable;
|
||||
}
|
||||
|
||||
internal void SendImmediately(NetConnection conn, NetOutgoingMessage msg)
|
||||
internal void SendImmediately(double now, NetConnection conn, NetOutgoingMessage msg)
|
||||
{
|
||||
NetException.Assert(msg.m_type == NetMessageType.Library, "SendImmediately can only send library (non-reliable) messages");
|
||||
|
||||
msg.m_inQueueCount = 1;
|
||||
int len = msg.Encode(m_sendBuffer, 0, conn);
|
||||
int len = msg.Encode(now, m_sendBuffer, 0, conn);
|
||||
Interlocked.Decrement(ref msg.m_inQueueCount);
|
||||
|
||||
SendPacket(len, conn.m_remoteEndpoint, 1);
|
||||
|
||||
@@ -144,18 +144,15 @@ namespace Lidgren.Network
|
||||
|
||||
for(int i=0;i<conn.m_storedMessages.Length;i++)
|
||||
{
|
||||
List<NetOutgoingMessage> list = conn.m_storedMessages[i];
|
||||
if (list != null && list.Count > 0)
|
||||
var dict = conn.m_storedMessages[i];
|
||||
if (dict != null)
|
||||
{
|
||||
foreach (NetOutgoingMessage om in conn.m_storedMessages[i])
|
||||
{
|
||||
if (om == msg)
|
||||
if (dict.ContainsValue(msg))
|
||||
throw new NetException("Ouch! Recycling stored message!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
NetException.Assert(msg.m_inQueueCount == 0, "Recycling message still in some queue!");
|
||||
|
||||
@@ -237,7 +234,7 @@ namespace Lidgren.Network
|
||||
else
|
||||
retval.Reset();
|
||||
|
||||
NetException.Assert(retval.m_status != NetIncomingMessageReleaseStatus.ReleasedToApplication);
|
||||
NetException.Assert(retval.m_status == NetIncomingMessageReleaseStatus.NotReleased);
|
||||
|
||||
retval.m_incomingType = tp;
|
||||
retval.m_senderConnection = null;
|
||||
@@ -265,6 +262,8 @@ namespace Lidgren.Network
|
||||
else
|
||||
retval.Reset();
|
||||
|
||||
NetException.Assert(retval.m_status == NetIncomingMessageReleaseStatus.NotReleased);
|
||||
|
||||
retval.m_data = GetStorage(copyLength);
|
||||
Buffer.BlockCopy(copyFrom, offset, retval.m_data, 0, copyLength);
|
||||
|
||||
|
||||
@@ -27,7 +27,8 @@ namespace ChatClient
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
MainForm = new Form1();
|
||||
|
||||
Client = new NetClient(new NetPeerConfiguration("Chat"));
|
||||
NetPeerConfiguration config = new NetPeerConfiguration("Chat");
|
||||
Client = new NetClient(config);
|
||||
Client.Start();
|
||||
|
||||
Display("Type 'connect <host>' to connect to a server");
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace ChatServer
|
||||
om.WriteAllProperties(cm, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
|
||||
|
||||
Display("Forwarding text from " + cm.Sender + " to all clients: " + cm.Text);
|
||||
Server.SendMessage(om, Server.Connections, NetDeliveryMethod.ReliableUnordered, 0);
|
||||
Server.SendMessage(om, Server.Connections, NetDeliveryMethod.ReliableOrdered, 0);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace ImageServer
|
||||
// send entire as a large message that will be automatically fragmented by the library
|
||||
om.Write(ImageData);
|
||||
|
||||
Server.SendMessage(om, inc.SenderConnection, NetDeliveryMethod.ReliableUnordered, 0);
|
||||
Server.SendMessage(om, inc.SenderConnection, NetDeliveryMethod.ReliableOrdered, 0);
|
||||
|
||||
// all messages will be sent before disconnect so we can call it here
|
||||
// inc.SenderConnection.Disconnect("Bye bye now");
|
||||
|
||||
Reference in New Issue
Block a user