You've already forked lidgren-network-gen3
mirror of
https://github.com/lidgren/lidgren-network-gen3.git
synced 2026-05-19 00:26:30 +09:00
Major refactoring of sending messages to multiple recipients
This commit is contained in:
@@ -25,6 +25,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BarebonesServer", "Samples\
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BarebonesClient", "Samples\BarebonesClient\BarebonesClient.csproj", "{BC0CBAEE-70FE-4B1E-A2FA-BCC731F1E48F}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BarebonesClient", "Samples\BarebonesClient\BarebonesClient.csproj", "{BC0CBAEE-70FE-4B1E-A2FA-BCC731F1E48F}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ManyServer", "Samples\ManyServer\ManyServer.csproj", "{44EFFA4A-C7FC-4C45-B84D-F13A391EF4E7}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ManyClients", "Samples\ManyClients\ManyClients.csproj", "{A41772F5-F20F-408D-ABD1-5D1C144853C6}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -75,6 +79,14 @@ Global
|
|||||||
{BC0CBAEE-70FE-4B1E-A2FA-BCC731F1E48F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{BC0CBAEE-70FE-4B1E-A2FA-BCC731F1E48F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{BC0CBAEE-70FE-4B1E-A2FA-BCC731F1E48F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{BC0CBAEE-70FE-4B1E-A2FA-BCC731F1E48F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{BC0CBAEE-70FE-4B1E-A2FA-BCC731F1E48F}.Release|Any CPU.Build.0 = Release|Any CPU
|
{BC0CBAEE-70FE-4B1E-A2FA-BCC731F1E48F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{44EFFA4A-C7FC-4C45-B84D-F13A391EF4E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{44EFFA4A-C7FC-4C45-B84D-F13A391EF4E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{44EFFA4A-C7FC-4C45-B84D-F13A391EF4E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{44EFFA4A-C7FC-4C45-B84D-F13A391EF4E7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A41772F5-F20F-408D-ABD1-5D1C144853C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A41772F5-F20F-408D-ABD1-5D1C144853C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A41772F5-F20F-408D-ABD1-5D1C144853C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A41772F5-F20F-408D-ABD1-5D1C144853C6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -89,5 +101,7 @@ Global
|
|||||||
{0B4B02BB-0F43-4466-A369-0682281AF60E} = {DA6697E7-4DD4-45EF-90A7-2FC265855019}
|
{0B4B02BB-0F43-4466-A369-0682281AF60E} = {DA6697E7-4DD4-45EF-90A7-2FC265855019}
|
||||||
{438173C5-8E95-4AE1-AAAB-5C1009F05302} = {DA6697E7-4DD4-45EF-90A7-2FC265855019}
|
{438173C5-8E95-4AE1-AAAB-5C1009F05302} = {DA6697E7-4DD4-45EF-90A7-2FC265855019}
|
||||||
{BC0CBAEE-70FE-4B1E-A2FA-BCC731F1E48F} = {DA6697E7-4DD4-45EF-90A7-2FC265855019}
|
{BC0CBAEE-70FE-4B1E-A2FA-BCC731F1E48F} = {DA6697E7-4DD4-45EF-90A7-2FC265855019}
|
||||||
|
{44EFFA4A-C7FC-4C45-B84D-F13A391EF4E7} = {DA6697E7-4DD4-45EF-90A7-2FC265855019}
|
||||||
|
{A41772F5-F20F-408D-ABD1-5D1C144853C6} = {DA6697E7-4DD4-45EF-90A7-2FC265855019}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
@@ -74,6 +74,7 @@
|
|||||||
<Compile Include="NetPeerStatus.cs" />
|
<Compile Include="NetPeerStatus.cs" />
|
||||||
<Compile Include="NetQueue.cs" />
|
<Compile Include="NetQueue.cs" />
|
||||||
<Compile Include="NetRandom.cs" />
|
<Compile Include="NetRandom.cs" />
|
||||||
|
<Compile Include="NetSending.cs" />
|
||||||
<Compile Include="NetServer.cs" />
|
<Compile Include="NetServer.cs" />
|
||||||
<Compile Include="NetTime.cs" />
|
<Compile Include="NetTime.cs" />
|
||||||
<Compile Include="NetUtility.cs" />
|
<Compile Include="NetUtility.cs" />
|
||||||
|
|||||||
@@ -84,7 +84,6 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
int len = 2 + m_peerConfiguration.AppIdentifier.Length + 8 + 4 + (m_approvalMessage == null ? 0 : m_approvalMessage.LengthBytes);
|
int len = 2 + m_peerConfiguration.AppIdentifier.Length + 8 + 4 + (m_approvalMessage == null ? 0 : m_approvalMessage.LengthBytes);
|
||||||
NetOutgoingMessage om = m_owner.CreateMessage(len);
|
NetOutgoingMessage om = m_owner.CreateMessage(len);
|
||||||
om.m_type = NetMessageType.Library;
|
|
||||||
om.m_libType = NetMessageLibraryType.Connect;
|
om.m_libType = NetMessageLibraryType.Connect;
|
||||||
om.Write(m_peerConfiguration.AppIdentifier);
|
om.Write(m_peerConfiguration.AppIdentifier);
|
||||||
om.Write(m_owner.m_uniqueIdentifier);
|
om.Write(m_owner.m_uniqueIdentifier);
|
||||||
@@ -100,10 +99,9 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
m_owner.LogVerbose("Sending Connect");
|
m_owner.LogVerbose("Sending Connect");
|
||||||
|
|
||||||
double now = NetTime.Now;
|
m_owner.SendLibraryImmediately(om, m_remoteEndpoint);
|
||||||
m_owner.SendImmediately(now, this, om);
|
|
||||||
|
|
||||||
m_connectInitationTime = now;
|
m_connectInitationTime = NetTime.Now;
|
||||||
SetStatus(NetConnectionStatus.Connecting, "Connecting");
|
SetStatus(NetConnectionStatus.Connecting, "Connecting");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -114,12 +112,11 @@ namespace Lidgren.Network
|
|||||||
double now = NetTime.Now;
|
double now = NetTime.Now;
|
||||||
|
|
||||||
NetOutgoingMessage reply = m_owner.CreateMessage(4);
|
NetOutgoingMessage reply = m_owner.CreateMessage(4);
|
||||||
reply.m_type = NetMessageType.Library;
|
|
||||||
reply.m_libType = NetMessageLibraryType.ConnectResponse;
|
reply.m_libType = NetMessageLibraryType.ConnectResponse;
|
||||||
reply.Write((float)now);
|
reply.Write((float)now);
|
||||||
|
|
||||||
m_owner.LogVerbose("Sending LibraryConnectResponse");
|
m_owner.LogVerbose("Sending LibraryConnectResponse");
|
||||||
m_owner.SendImmediately(now, this, reply);
|
m_owner.SendLibraryImmediately(reply, m_remoteEndpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void SendConnectionEstablished()
|
internal void SendConnectionEstablished()
|
||||||
@@ -127,12 +124,11 @@ namespace Lidgren.Network
|
|||||||
double now = NetTime.Now;
|
double now = NetTime.Now;
|
||||||
|
|
||||||
NetOutgoingMessage ce = m_owner.CreateMessage(4);
|
NetOutgoingMessage ce = m_owner.CreateMessage(4);
|
||||||
ce.m_type = NetMessageType.Library;
|
|
||||||
ce.m_libType = NetMessageLibraryType.ConnectionEstablished;
|
ce.m_libType = NetMessageLibraryType.ConnectionEstablished;
|
||||||
ce.Write((float)now);
|
ce.Write((float)now);
|
||||||
|
|
||||||
m_owner.LogVerbose("Sending LibraryConnectionEstablished");
|
m_owner.LogVerbose("Sending LibraryConnectionEstablished");
|
||||||
m_owner.SendImmediately(now, this, ce);
|
m_owner.SendLibraryImmediately(ce, m_remoteEndpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ExecuteDisconnect(bool sendByeMessage)
|
internal void ExecuteDisconnect(bool sendByeMessage)
|
||||||
@@ -145,7 +141,7 @@ namespace Lidgren.Network
|
|||||||
if (sendByeMessage)
|
if (sendByeMessage)
|
||||||
{
|
{
|
||||||
NetOutgoingMessage om = m_owner.CreateLibraryMessage(NetMessageLibraryType.Disconnect, m_disconnectByeMessage);
|
NetOutgoingMessage om = m_owner.CreateLibraryMessage(NetMessageLibraryType.Disconnect, m_disconnectByeMessage);
|
||||||
EnqueueOutgoingMessage(om);
|
SendLibrary(om);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_owner.LogVerbose("Executing Disconnect(" + m_disconnectByeMessage + ")");
|
m_owner.LogVerbose("Executing Disconnect(" + m_disconnectByeMessage + ")");
|
||||||
@@ -163,12 +159,7 @@ namespace Lidgren.Network
|
|||||||
m_owner.LogVerbose("Finishing Disconnect(" + m_disconnectByeMessage + ")");
|
m_owner.LogVerbose("Finishing Disconnect(" + m_disconnectByeMessage + ")");
|
||||||
|
|
||||||
// release some held memory
|
// release some held memory
|
||||||
if (m_storedMessages != null)
|
m_unackedSends.Clear();
|
||||||
{
|
|
||||||
foreach (var dict in m_storedMessages)
|
|
||||||
if (dict != null)
|
|
||||||
dict.Clear();
|
|
||||||
}
|
|
||||||
m_acknowledgesToSend.Clear();
|
m_acknowledgesToSend.Clear();
|
||||||
|
|
||||||
SetStatus(NetConnectionStatus.Disconnected, m_disconnectByeMessage);
|
SetStatus(NetConnectionStatus.Disconnected, m_disconnectByeMessage);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ namespace Lidgren.Network
|
|||||||
private byte m_lastSentPingNumber;
|
private byte m_lastSentPingNumber;
|
||||||
private double m_lastPingSendTime;
|
private double m_lastPingSendTime;
|
||||||
private double m_nextPing;
|
private double m_nextPing;
|
||||||
private double m_lastSendRespondedTo;
|
internal double m_lastSendRespondedTo;
|
||||||
|
|
||||||
// remote + diff = local
|
// remote + diff = local
|
||||||
// diff = local - remote
|
// diff = local - remote
|
||||||
@@ -62,14 +62,12 @@ namespace Lidgren.Network
|
|||||||
double now = NetTime.Now;
|
double now = NetTime.Now;
|
||||||
|
|
||||||
// send pong
|
// send pong
|
||||||
NetOutgoingMessage pong = m_owner.CreateMessage(1);
|
NetOutgoingMessage pong = m_owner.CreateMessage(1 + 8);
|
||||||
pong.m_type = NetMessageType.Library;
|
|
||||||
pong.m_libType = NetMessageLibraryType.Pong;
|
pong.m_libType = NetMessageLibraryType.Pong;
|
||||||
pong.Write((byte)pingNumber);
|
pong.Write((byte)pingNumber);
|
||||||
pong.Write(now);
|
pong.Write(now);
|
||||||
|
|
||||||
// send immediately
|
m_owner.SendLibraryImmediately(pong, m_remoteEndpoint);
|
||||||
m_owner.SendImmediately(now, this, pong);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void HandleIncomingPong(double receiveNow, byte pingNumber, double remoteNetTime)
|
internal void HandleIncomingPong(double receiveNow, byte pingNumber, double remoteNetTime)
|
||||||
@@ -122,9 +120,8 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
// send keepalive thru regular channels to give acks something to piggyback on
|
// send keepalive thru regular channels to give acks something to piggyback on
|
||||||
NetOutgoingMessage pig = m_owner.CreateMessage(1);
|
NetOutgoingMessage pig = m_owner.CreateMessage(1);
|
||||||
pig.m_type = NetMessageType.Library;
|
|
||||||
pig.m_libType = NetMessageLibraryType.KeepAlive;
|
pig.m_libType = NetMessageLibraryType.KeepAlive;
|
||||||
EnqueueOutgoingMessage(pig);
|
SendLibrary(pig);
|
||||||
m_nextForceAckTime = now + m_peerConfiguration.m_maxAckDelayTime;
|
m_nextForceAckTime = now + m_peerConfiguration.m_maxAckDelayTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,17 +138,17 @@ namespace Lidgren.Network
|
|||||||
//
|
//
|
||||||
// send ping
|
// send ping
|
||||||
//
|
//
|
||||||
|
now = NetTime.Now; // need exact number
|
||||||
m_lastSentPingNumber++;
|
m_lastSentPingNumber++;
|
||||||
|
m_lastPingSendTime = now;
|
||||||
|
m_nextPing = now + m_owner.Configuration.m_pingFrequency;
|
||||||
|
|
||||||
NetOutgoingMessage ping = m_owner.CreateMessage(1);
|
NetOutgoingMessage ping = m_owner.CreateMessage(1);
|
||||||
ping.m_type = NetMessageType.Library;
|
|
||||||
ping.m_libType = NetMessageLibraryType.Ping;
|
ping.m_libType = NetMessageLibraryType.Ping;
|
||||||
ping.Write((byte)m_lastSentPingNumber);
|
ping.Write((byte)m_lastSentPingNumber);
|
||||||
|
|
||||||
m_owner.SendImmediately(now, this, ping);
|
m_owner.SendLibraryImmediately(ping, m_remoteEndpoint);
|
||||||
|
|
||||||
m_lastPingSendTime = NetTime.Now; // need exact number
|
|
||||||
m_nextPing = now + m_owner.Configuration.m_pingFrequency;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,11 +25,13 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
public partial class NetConnection
|
public partial class NetConnection
|
||||||
{
|
{
|
||||||
private ushort[] m_nextSendSequenceNumber;
|
private int[] m_nextSendSequenceNumber;
|
||||||
private ushort[] m_lastReceivedSequenced;
|
private ushort[] m_lastReceivedSequenced;
|
||||||
|
|
||||||
internal readonly Dictionary<ushort, NetOutgoingMessage>[] m_storedMessages = new Dictionary<ushort, NetOutgoingMessage>[NetConstants.NumReliableChannels];
|
internal readonly List<NetSending> m_unackedSends = new List<NetSending>();
|
||||||
internal readonly Dictionary<NetOutgoingMessage, ushort>[] m_inverseStored = new Dictionary<NetOutgoingMessage, ushort>[NetConstants.NumReliableChannels];
|
|
||||||
|
//internal readonly Dictionary<ushort, NetOutgoingMessage>[] m_storedMessages = new Dictionary<ushort, NetOutgoingMessage>[NetConstants.NumReliableChannels];
|
||||||
|
//internal readonly Dictionary<NetOutgoingMessage, ushort>[] m_inverseStored = new Dictionary<NetOutgoingMessage, ushort>[NetConstants.NumReliableChannels];
|
||||||
internal readonly NetBitVector m_storedMessagesNotEmpty = new NetBitVector(NetConstants.NumReliableChannels);
|
internal readonly NetBitVector m_storedMessagesNotEmpty = new NetBitVector(NetConstants.NumReliableChannels);
|
||||||
|
|
||||||
private readonly ushort[] m_nextExpectedReliableSequence = new ushort[NetConstants.NumReliableChannels];
|
private readonly ushort[] m_nextExpectedReliableSequence = new ushort[NetConstants.NumReliableChannels];
|
||||||
@@ -41,14 +43,7 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
public int GetStoredMessagesCount()
|
public int GetStoredMessagesCount()
|
||||||
{
|
{
|
||||||
int retval = 0;
|
return m_unackedSends.Count;
|
||||||
for (int i = 0; i < m_storedMessages.Length; i++)
|
|
||||||
{
|
|
||||||
var list = m_storedMessages[i];
|
|
||||||
if (list != null)
|
|
||||||
retval += list.Count;
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetWithheldMessagesCount()
|
public int GetWithheldMessagesCount()
|
||||||
@@ -66,16 +61,17 @@ namespace Lidgren.Network
|
|||||||
private void InitializeReliability()
|
private void InitializeReliability()
|
||||||
{
|
{
|
||||||
int num = ((int)NetMessageType.UserReliableOrdered + NetConstants.NetChannelsPerDeliveryMethod) - (int)NetMessageType.UserSequenced;
|
int num = ((int)NetMessageType.UserReliableOrdered + NetConstants.NetChannelsPerDeliveryMethod) - (int)NetMessageType.UserSequenced;
|
||||||
m_nextSendSequenceNumber = new ushort[num];
|
m_nextSendSequenceNumber = new int[num];
|
||||||
|
for(int i=0;i<m_nextSendSequenceNumber.Length;i++)
|
||||||
|
m_nextSendSequenceNumber[i] = -1; // initialize to -1; pre-increment will start sending at 0
|
||||||
m_lastReceivedSequenced = new ushort[num];
|
m_lastReceivedSequenced = new ushort[num];
|
||||||
m_nextForceAckTime = double.MaxValue;
|
m_nextForceAckTime = double.MaxValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ushort GetSendSequenceNumber(NetMessageType mtp)
|
internal ushort GetSendSequenceNumber(NetMessageType mtp)
|
||||||
{
|
{
|
||||||
m_owner.VerifyNetworkThread();
|
|
||||||
int slot = (int)mtp - (int)NetMessageType.UserSequenced;
|
int slot = (int)mtp - (int)NetMessageType.UserSequenced;
|
||||||
return m_nextSendSequenceNumber[slot]++;
|
return (ushort)Interlocked.Increment(ref m_nextSendSequenceNumber[slot]);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static int Relate(int seqNr, int lastReceived)
|
internal static int Relate(int seqNr, int lastReceived)
|
||||||
@@ -99,6 +95,7 @@ namespace Lidgren.Network
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// called by Encode() to retrieve a sequence number and store the message for potential resending
|
// called by Encode() to retrieve a sequence number and store the message for potential resending
|
||||||
internal ushort StoreReliableMessage(double now, NetOutgoingMessage msg)
|
internal ushort StoreReliableMessage(double now, NetOutgoingMessage msg)
|
||||||
{
|
{
|
||||||
@@ -159,36 +156,7 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
return (ushort)seqNr;
|
return (ushort)seqNr;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
private void Resend(double now, ushort seqNr, NetOutgoingMessage msg)
|
|
||||||
{
|
|
||||||
m_owner.VerifyNetworkThread();
|
|
||||||
|
|
||||||
int numSends = msg.m_numSends;
|
|
||||||
float[] baseTimes = m_peerConfiguration.m_resendBaseTime;
|
|
||||||
if (numSends >= baseTimes.Length)
|
|
||||||
{
|
|
||||||
// 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 + " (seqNr " + seqNr + ")");
|
|
||||||
|
|
||||||
Disconnect("Failed to deliver reliable message!");
|
|
||||||
|
|
||||||
return; // bye
|
|
||||||
}
|
|
||||||
|
|
||||||
m_owner.LogVerbose("Resending " + msg + " (seqNr " + seqNr + ")");
|
|
||||||
|
|
||||||
Interlocked.Increment(ref msg.m_inQueueCount);
|
|
||||||
m_unsentMessages.EnqueueFirst(msg);
|
|
||||||
|
|
||||||
msg.m_lastSentTime = now;
|
|
||||||
|
|
||||||
// schedule next resend
|
|
||||||
float[] multiplers = m_peerConfiguration.m_resendRTTMultiplier;
|
|
||||||
msg.m_nextResendTime = now + baseTimes[numSends] + (m_averageRoundtripTime * multiplers[numSends]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleIncomingAcks(int ptr, int payloadByteLength)
|
private void HandleIncomingAcks(int ptr, int payloadByteLength)
|
||||||
{
|
{
|
||||||
@@ -205,6 +173,25 @@ namespace Lidgren.Network
|
|||||||
NetMessageType tp = (NetMessageType)buffer[ptr++];
|
NetMessageType tp = (NetMessageType)buffer[ptr++];
|
||||||
//m_owner.LogDebug("Got ack for " + tp + "|" + seqNr);
|
//m_owner.LogDebug("Got ack for " + tp + "|" + seqNr);
|
||||||
|
|
||||||
|
foreach(NetSending send in m_unackedSends)
|
||||||
|
{
|
||||||
|
if (send.MessageType == tp && send.SequenceNumber == seqNr)
|
||||||
|
{
|
||||||
|
// found it
|
||||||
|
m_lastSendRespondedTo = NetTime.Now; // TODO: calculate from send.NextResend and send.NumSends
|
||||||
|
int unfin = send.Message.m_numUnfinishedSendings;
|
||||||
|
send.Message.m_numUnfinishedSendings = unfin - 1;
|
||||||
|
if (unfin <= 1)
|
||||||
|
m_owner.Recycle(send.Message); // every sent has been acked; free the message
|
||||||
|
|
||||||
|
m_unackedSends.Remove(send);
|
||||||
|
|
||||||
|
// TODO: recycle send
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// remove stored message
|
// remove stored message
|
||||||
int reliableSlot = (int)tp - (int)NetMessageType.UserReliableUnordered;
|
int reliableSlot = (int)tp - (int)NetMessageType.UserReliableUnordered;
|
||||||
|
|
||||||
@@ -220,6 +207,9 @@ namespace Lidgren.Network
|
|||||||
dict.Remove(seqNr);
|
dict.Remove(seqNr);
|
||||||
m_inverseStored[reliableSlot].Remove(om);
|
m_inverseStored[reliableSlot].Remove(om);
|
||||||
|
|
||||||
|
if (dict.Count < 1)
|
||||||
|
m_storedMessagesNotEmpty[reliableSlot] = false;
|
||||||
|
|
||||||
Interlocked.Decrement(ref om.m_inQueueCount);
|
Interlocked.Decrement(ref om.m_inQueueCount);
|
||||||
|
|
||||||
NetException.Assert(om.m_lastSentTime != 0);
|
NetException.Assert(om.m_lastSentTime != 0);
|
||||||
@@ -230,6 +220,7 @@ namespace Lidgren.Network
|
|||||||
if (om.m_inQueueCount < 1)
|
if (om.m_inQueueCount < 1)
|
||||||
m_owner.Recycle(om);
|
m_owner.Recycle(om);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// TODO: receipt handling
|
// TODO: receipt handling
|
||||||
}
|
}
|
||||||
@@ -251,6 +242,10 @@ namespace Lidgren.Network
|
|||||||
received[(nextExpected + (NetConstants.NumSequenceNumbers / 2)) % NetConstants.NumSequenceNumbers] = false; // reset for next pass
|
received[(nextExpected + (NetConstants.NumSequenceNumbers / 2)) % NetConstants.NumSequenceNumbers] = false; // reset for next pass
|
||||||
nextExpected = (nextExpected + 1) % NetConstants.NumSequenceNumbers;
|
nextExpected = (nextExpected + 1) % NetConstants.NumSequenceNumbers;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Release withheld messages
|
||||||
|
//
|
||||||
|
|
||||||
while (received[nextExpected] == true)
|
while (received[nextExpected] == true)
|
||||||
{
|
{
|
||||||
// it seems we've already received the next expected reliable sequence number
|
// it seems we've already received the next expected reliable sequence number
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
private static readonly NetFragmentationInfo s_genericFragmentationInfo = new NetFragmentationInfo();
|
private static readonly NetFragmentationInfo s_genericFragmentationInfo = new NetFragmentationInfo();
|
||||||
|
|
||||||
private readonly NetPeer m_owner;
|
internal readonly NetPeer m_owner;
|
||||||
internal readonly IPEndPoint m_remoteEndpoint;
|
internal readonly IPEndPoint m_remoteEndpoint;
|
||||||
internal double m_lastHeardFrom;
|
internal double m_lastHeardFrom;
|
||||||
internal NetQueue<NetOutgoingMessage> m_unsentMessages;
|
internal readonly NetQueue<NetSending> m_unsentMessages;
|
||||||
internal NetConnectionStatus m_status;
|
internal NetConnectionStatus m_status;
|
||||||
private NetConnectionStatus m_visibleStatus;
|
private NetConnectionStatus m_visibleStatus;
|
||||||
private double m_lastSentUnsentMessages;
|
private double m_lastSentUnsentMessages;
|
||||||
@@ -91,10 +91,10 @@ namespace Lidgren.Network
|
|||||||
m_owner = owner;
|
m_owner = owner;
|
||||||
m_peerConfiguration = m_owner.m_configuration;
|
m_peerConfiguration = m_owner.m_configuration;
|
||||||
m_remoteEndpoint = remoteEndpoint;
|
m_remoteEndpoint = remoteEndpoint;
|
||||||
m_unsentMessages = new NetQueue<NetOutgoingMessage>(16);
|
|
||||||
m_fragmentGroups = new Dictionary<int, NetIncomingMessage>();
|
m_fragmentGroups = new Dictionary<int, NetIncomingMessage>();
|
||||||
m_status = NetConnectionStatus.None;
|
m_status = NetConnectionStatus.None;
|
||||||
m_visibleStatus = NetConnectionStatus.None;
|
m_visibleStatus = NetConnectionStatus.None;
|
||||||
|
m_unsentMessages = new NetQueue<NetSending>(8);
|
||||||
|
|
||||||
double now = NetTime.Now;
|
double now = NetTime.Now;
|
||||||
m_nextPing = now + 5.0f;
|
m_nextPing = now + 5.0f;
|
||||||
@@ -143,21 +143,41 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
|
|
||||||
// queue resends
|
// queue resends
|
||||||
|
foreach (NetSending send in m_unackedSends)
|
||||||
|
{
|
||||||
|
if (now > send.NextResend)
|
||||||
|
{
|
||||||
|
m_unsentMessages.EnqueueFirst(send);
|
||||||
|
send.SetNextResend(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
if (!m_storedMessagesNotEmpty.IsEmpty())
|
if (!m_storedMessagesNotEmpty.IsEmpty())
|
||||||
{
|
{
|
||||||
int first = m_storedMessagesNotEmpty.GetFirstSetIndex();
|
int first = m_storedMessagesNotEmpty.GetFirstSetIndex();
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
// slow slow verification
|
||||||
|
for (int i = 0; i < first; i++)
|
||||||
|
if (m_storedMessages[i] != null && m_storedMessages[i].Count > 0)
|
||||||
|
throw new NetException("m_storedMessagesNotEmpty mismatch; first is " + first + " but actual first is " + i);
|
||||||
|
if (m_storedMessages[first] == null || m_storedMessages[first].Count < 1)
|
||||||
|
throw new NetException("m_storedMessagesNotEmpty failure; first is " + first + ", but that entry is empty!");
|
||||||
|
#endif
|
||||||
for (int i = first; i < m_storedMessages.Length; i++)
|
for (int i = first; i < m_storedMessages.Length; i++)
|
||||||
{
|
{
|
||||||
if (m_storedMessagesNotEmpty.Get(i))
|
if (m_storedMessagesNotEmpty.Get(i))
|
||||||
{
|
{
|
||||||
Dictionary<ushort, NetOutgoingMessage> dict = m_storedMessages[i];
|
Dictionary<ushort, NetOutgoingMessage> dict = m_storedMessages[i];
|
||||||
|
RestartCheck:
|
||||||
foreach (ushort seqNr in m_storedMessages[i].Keys)
|
foreach (ushort seqNr in m_storedMessages[i].Keys)
|
||||||
{
|
{
|
||||||
NetOutgoingMessage om = dict[seqNr];
|
NetOutgoingMessage om = dict[seqNr];
|
||||||
if (now >= om.m_nextResendTime)
|
if (now >= om.m_nextResendTime)
|
||||||
{
|
{
|
||||||
Resend(now, seqNr, om);
|
Resend(now, seqNr, om);
|
||||||
break; // need to break out here; collection may have been modified
|
goto RestartCheck; // need to break out here; collection may have been modified
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -169,6 +189,7 @@ namespace Lidgren.Network
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// send unsent messages; high priority first
|
// send unsent messages; high priority first
|
||||||
@@ -199,13 +220,14 @@ namespace Lidgren.Network
|
|||||||
if (m_throttleDebt >= throttleThreshold)
|
if (m_throttleDebt >= throttleThreshold)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
NetOutgoingMessage msg = m_unsentMessages.TryDequeue();
|
NetSending send = m_unsentMessages.TryDequeue();
|
||||||
if (msg == null)
|
if (send == null)
|
||||||
continue;
|
continue;
|
||||||
Interlocked.Decrement(ref msg.m_inQueueCount);
|
|
||||||
|
|
||||||
|
send.NumSends++;
|
||||||
|
|
||||||
|
NetOutgoingMessage msg = send.Message;
|
||||||
int msgPayloadLength = msg.LengthBytes;
|
int msgPayloadLength = msg.LengthBytes;
|
||||||
msg.m_lastSentTime = now;
|
|
||||||
|
|
||||||
if (ptr > 0)
|
if (ptr > 0)
|
||||||
{
|
{
|
||||||
@@ -233,9 +255,27 @@ namespace Lidgren.Network
|
|||||||
// encode message
|
// encode message
|
||||||
//
|
//
|
||||||
|
|
||||||
ptr = msg.Encode(now, buffer, ptr, this);
|
if (send.FragmentGroupId > 0)
|
||||||
|
ptr = msg.EncodeFragmented(buffer, ptr, send, mtu);
|
||||||
|
else
|
||||||
|
ptr = msg.EncodeUnfragmented(buffer, ptr, send.MessageType, send.SequenceNumber);
|
||||||
numIncludedMessages++;
|
numIncludedMessages++;
|
||||||
|
|
||||||
|
if (send.MessageType >= NetMessageType.UserReliableUnordered)
|
||||||
|
{
|
||||||
|
// store for reliability
|
||||||
|
if (send.NumSends == 0)
|
||||||
|
m_unackedSends.Add(send);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// unreliable message; recycle if all sendings done
|
||||||
|
int unfin = msg.m_numUnfinishedSendings;
|
||||||
|
msg.m_numUnfinishedSendings = unfin - 1;
|
||||||
|
if (unfin <= 1)
|
||||||
|
m_owner.Recycle(msg);
|
||||||
|
}
|
||||||
|
|
||||||
// room to piggyback some acks?
|
// room to piggyback some acks?
|
||||||
if (m_acknowledgesToSend.Count > 0)
|
if (m_acknowledgesToSend.Count > 0)
|
||||||
{
|
{
|
||||||
@@ -250,14 +290,11 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.m_type == NetMessageType.Library && msg.m_libType == NetMessageLibraryType.Disconnect)
|
if (send.MessageType == NetMessageType.Library && msg.m_libType == NetMessageLibraryType.Disconnect)
|
||||||
{
|
{
|
||||||
FinishDisconnect();
|
FinishDisconnect();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.m_inQueueCount < 1)
|
|
||||||
m_owner.Recycle(msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptr > 0)
|
if (ptr > 0)
|
||||||
@@ -368,13 +405,12 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
|
|
||||||
// It's an early reliable message
|
// It's an early reliable message
|
||||||
recList[channelSequenceNumber] = true;
|
|
||||||
|
|
||||||
m_owner.LogVerbose("Received early reliable message: " + channelSequenceNumber);
|
m_owner.LogVerbose("Received early reliable message: " + channelSequenceNumber);
|
||||||
|
|
||||||
//
|
//
|
||||||
// It's not a duplicate; mark as received. Release if it's unordered, else withhold
|
// It's not a duplicate; mark as received. Release if it's unordered, else withhold
|
||||||
//
|
//
|
||||||
|
recList[channelSequenceNumber] = true;
|
||||||
|
|
||||||
if (ndm == NetDeliveryMethod.ReliableUnordered)
|
if (ndm == NetDeliveryMethod.ReliableUnordered)
|
||||||
{
|
{
|
||||||
@@ -563,43 +599,58 @@ namespace Lidgren.Network
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendMessage(NetOutgoingMessage msg, NetDeliveryMethod method)
|
internal void SendLibrary(NetOutgoingMessage msg)
|
||||||
{
|
{
|
||||||
if (msg.IsSent)
|
NetException.Assert(msg.m_libType != NetMessageLibraryType.Error);
|
||||||
throw new NetException("Message has already been sent!");
|
|
||||||
msg.m_type = (NetMessageType)method;
|
NetSending send = new NetSending(msg, NetMessageType.Library, 0);
|
||||||
EnqueueOutgoingMessage(msg);
|
|
||||||
|
msg.m_wasSent = true;
|
||||||
|
msg.m_numUnfinishedSendings++;
|
||||||
|
m_unsentMessages.Enqueue(send);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendMessage(NetOutgoingMessage msg, NetDeliveryMethod method, int sequenceChannel)
|
public void SendMessage(NetOutgoingMessage msg, NetDeliveryMethod method)
|
||||||
{
|
{
|
||||||
|
SendMessage(msg, method, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SendMessage(NetOutgoingMessage msg, NetDeliveryMethod method, int sequenceChannel)
|
||||||
|
{
|
||||||
|
NetException.Assert(msg.m_libType == NetMessageLibraryType.Error, "Use SendLibrary() instead!");
|
||||||
|
|
||||||
if (msg.IsSent)
|
if (msg.IsSent)
|
||||||
throw new NetException("Message has already been sent!");
|
throw new NetException("Message has already been sent!");
|
||||||
|
|
||||||
NetException.Assert(sequenceChannel >= 0 && sequenceChannel < NetConstants.NetChannelsPerDeliveryMethod, "Sequence channel must be between 0 and NetConstants.NetChannelsPerDeliveryMethod (" + NetConstants.NetChannelsPerDeliveryMethod + ")");
|
NetException.Assert(sequenceChannel >= 0 && sequenceChannel < NetConstants.NetChannelsPerDeliveryMethod, "Sequence channel must be between 0 and NetConstants.NetChannelsPerDeliveryMethod (" + NetConstants.NetChannelsPerDeliveryMethod + ")");
|
||||||
|
|
||||||
msg.m_type = (NetMessageType)((int)method + sequenceChannel);
|
if (m_owner == null)
|
||||||
EnqueueOutgoingMessage(msg);
|
return false; // we've been disposed
|
||||||
|
|
||||||
|
msg.m_wasSent = true;
|
||||||
|
|
||||||
|
NetMessageType tp = (NetMessageType)((int)method + sequenceChannel);
|
||||||
|
return EnqueueSendMessage(msg, tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// called by user and network thread
|
internal bool EnqueueSendMessage(NetOutgoingMessage msg, NetMessageType tp)
|
||||||
internal void EnqueueOutgoingMessage(NetOutgoingMessage msg)
|
|
||||||
{
|
{
|
||||||
if (m_owner == null)
|
|
||||||
return; // we've been disposed
|
|
||||||
|
|
||||||
int msgLen = msg.LengthBytes;
|
int msgLen = msg.LengthBytes;
|
||||||
int mtu = m_owner.m_configuration.m_maximumTransmissionUnit;
|
int mtu = m_owner.m_configuration.m_maximumTransmissionUnit;
|
||||||
|
|
||||||
if (msgLen <= mtu)
|
if (msgLen <= mtu)
|
||||||
{
|
{
|
||||||
Interlocked.Increment(ref msg.m_inQueueCount);
|
NetSending send = new NetSending(msg, tp, GetSendSequenceNumber(tp));
|
||||||
m_unsentMessages.Enqueue(msg);
|
msg.m_numUnfinishedSendings++;
|
||||||
return;
|
|
||||||
|
send.SetNextResend(this);
|
||||||
|
|
||||||
|
m_unsentMessages.Enqueue(send);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if ((int)msg.m_type < (int)NetMessageType.UserReliableUnordered)
|
if (tp < NetMessageType.UserReliableUnordered)
|
||||||
{
|
{
|
||||||
// unreliable
|
// unreliable
|
||||||
m_owner.LogWarning("Sending more than MTU (currently " + mtu + ") bytes unreliably is not recommended!");
|
m_owner.LogWarning("Sending more than MTU (currently " + mtu + ") bytes unreliably is not recommended!");
|
||||||
@@ -609,6 +660,7 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
// message must be fragmented
|
// message must be fragmented
|
||||||
int fgi = Interlocked.Increment(ref m_nextFragmentGroupId);
|
int fgi = Interlocked.Increment(ref m_nextFragmentGroupId);
|
||||||
|
// TODO: loop group id?
|
||||||
|
|
||||||
int numFragments = (msgLen + mtu - 1) / mtu;
|
int numFragments = (msgLen + mtu - 1) / mtu;
|
||||||
|
|
||||||
@@ -616,16 +668,16 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
int flen = (i == numFragments - 1 ? (msgLen - (mtu * (numFragments - 1))) : mtu);
|
int flen = (i == numFragments - 1 ? (msgLen - (mtu * (numFragments - 1))) : mtu);
|
||||||
|
|
||||||
NetOutgoingMessage fm = m_owner.CreateMessage(flen);
|
NetSending fs = new NetSending(msg, tp, GetSendSequenceNumber(tp));
|
||||||
fm.m_fragmentGroupId = fgi;
|
fs.FragmentGroupId = fgi;
|
||||||
fm.m_fragmentNumber = i;
|
fs.FragmentNumber = i;
|
||||||
fm.m_fragmentTotalCount = numFragments;
|
fs.FragmentTotalCount = numFragments;
|
||||||
|
msg.m_numUnfinishedSendings++;
|
||||||
fm.Write(msg.m_data, mtu * i, flen);
|
m_unsentMessages.Enqueue(fs);
|
||||||
fm.m_type = msg.m_type;
|
fs.SetNextResend(this);
|
||||||
Interlocked.Increment(ref fm.m_inQueueCount);
|
|
||||||
m_unsentMessages.Enqueue(fm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Disconnect(string byeMessage)
|
public void Disconnect(string byeMessage)
|
||||||
@@ -640,26 +692,13 @@ namespace Lidgren.Network
|
|||||||
// loosen up throttling
|
// loosen up throttling
|
||||||
m_throttleDebt = -m_owner.m_configuration.m_throttlePeakBytes;
|
m_throttleDebt = -m_owner.m_configuration.m_throttlePeakBytes;
|
||||||
|
|
||||||
// shorten resend times
|
// instantly resend all unacked
|
||||||
for (int i = 0; i < m_storedMessages.Length; i++)
|
double now = NetTime.Now;
|
||||||
{
|
foreach(NetSending send in m_unackedSends)
|
||||||
Dictionary<ushort, NetOutgoingMessage> dict = m_storedMessages[i];
|
send.NextResend = now;
|
||||||
if (dict != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
foreach (NetOutgoingMessage om in dict.Values)
|
|
||||||
om.m_nextResendTime = (om.m_nextResendTime * 0.8) - 0.05;
|
|
||||||
}
|
|
||||||
catch (InvalidOperationException)
|
|
||||||
{
|
|
||||||
// ok, collection was modified, never mind then - it was worth a shot
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NetOutgoingMessage bye = m_owner.CreateLibraryMessage(NetMessageLibraryType.Disconnect, byeMessage);
|
NetOutgoingMessage bye = m_owner.CreateLibraryMessage(NetMessageLibraryType.Disconnect, byeMessage);
|
||||||
EnqueueOutgoingMessage(bye);
|
SendLibrary(bye);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Approve()
|
public void Approve()
|
||||||
|
|||||||
@@ -72,6 +72,20 @@ namespace Lidgren.Network
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int ReceivedBytes { get { return m_receivedBytes; } }
|
public int ReceivedBytes { get { return m_receivedBytes; } }
|
||||||
|
|
||||||
|
public double LastSendRespondedTo { get { return m_connection.m_lastSendRespondedTo; } }
|
||||||
|
|
||||||
|
public int MostSends
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
int most = 0;
|
||||||
|
foreach (var a in m_connection.m_unackedSends)
|
||||||
|
if (a.NumSends > most)
|
||||||
|
most = a.NumSends;
|
||||||
|
return most;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Conditional("DEBUG")]
|
[Conditional("DEBUG")]
|
||||||
internal void PacketSent(int numBytes, int numMessages)
|
internal void PacketSent(int numBytes, int numMessages)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,21 +18,23 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
// send message to client
|
// send message to client
|
||||||
NetOutgoingMessage msg = CreateMessage(10 + token.Length + 1);
|
NetOutgoingMessage msg = CreateMessage(10 + token.Length + 1);
|
||||||
|
msg.m_libType = NetMessageLibraryType.NatIntroduction;
|
||||||
msg.Write(false);
|
msg.Write(false);
|
||||||
msg.WritePadBits();
|
msg.WritePadBits();
|
||||||
msg.Write(hostInternal);
|
msg.Write(hostInternal);
|
||||||
msg.Write(hostExternal);
|
msg.Write(hostExternal);
|
||||||
msg.Write(token);
|
msg.Write(token);
|
||||||
SendUnconnectedLibraryMessage(msg, NetMessageLibraryType.NatIntroduction, clientExternal);
|
SendUnconnectedLibrary(msg, clientExternal);
|
||||||
|
|
||||||
// send message to host
|
// send message to host
|
||||||
msg = CreateMessage(10 + token.Length + 1);
|
msg = CreateMessage(10 + token.Length + 1);
|
||||||
|
msg.m_libType = NetMessageLibraryType.NatIntroduction;
|
||||||
msg.Write(true);
|
msg.Write(true);
|
||||||
msg.WritePadBits();
|
msg.WritePadBits();
|
||||||
msg.Write(clientInternal);
|
msg.Write(clientInternal);
|
||||||
msg.Write(clientExternal);
|
msg.Write(clientExternal);
|
||||||
msg.Write(token);
|
msg.Write(token);
|
||||||
SendUnconnectedLibraryMessage(msg, NetMessageLibraryType.NatIntroduction, hostExternal);
|
SendUnconnectedLibrary(msg, hostExternal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -60,15 +62,17 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
// send internal punch
|
// send internal punch
|
||||||
punch = CreateMessage(1);
|
punch = CreateMessage(1);
|
||||||
|
punch.m_libType = NetMessageLibraryType.NatPunchMessage;
|
||||||
punch.Write(hostByte);
|
punch.Write(hostByte);
|
||||||
punch.Write(token);
|
punch.Write(token);
|
||||||
SendUnconnectedLibraryMessage(punch, NetMessageLibraryType.NatPunchMessage, remoteInternal);
|
SendUnconnectedLibrary(punch, remoteInternal);
|
||||||
|
|
||||||
// send external punch
|
// send external punch
|
||||||
punch = CreateMessage(1);
|
punch = CreateMessage(1);
|
||||||
|
punch.m_libType = NetMessageLibraryType.NatPunchMessage;
|
||||||
punch.Write(hostByte);
|
punch.Write(hostByte);
|
||||||
punch.Write(token);
|
punch.Write(token);
|
||||||
SendUnconnectedLibraryMessage(punch, NetMessageLibraryType.NatPunchMessage, remoteExternal);
|
SendUnconnectedLibrary(punch, remoteExternal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -28,40 +28,32 @@ namespace Lidgren.Network
|
|||||||
public sealed partial class NetOutgoingMessage
|
public sealed partial class NetOutgoingMessage
|
||||||
{
|
{
|
||||||
// reference count before message can be recycled
|
// reference count before message can be recycled
|
||||||
internal int m_inQueueCount;
|
internal int m_numUnfinishedSendings;
|
||||||
|
|
||||||
internal NetMessageType m_type;
|
internal bool m_wasSent; // true is SendMessage() public method has been called
|
||||||
internal NetMessageLibraryType m_libType;
|
internal NetMessageLibraryType m_libType = NetMessageLibraryType.Error;
|
||||||
|
|
||||||
internal IPEndPoint m_unconnectedRecipient;
|
//internal int m_fragmentGroupId;
|
||||||
|
//internal int m_fragmentNumber;
|
||||||
internal double m_lastSentTime; // when was this message sent last?
|
//internal int m_fragmentTotalCount;
|
||||||
internal double m_nextResendTime; // when to resend this message the next time
|
|
||||||
internal int m_numSends; // the number of times this message has been sent/resent
|
|
||||||
|
|
||||||
internal int m_fragmentGroupId;
|
|
||||||
internal int m_fragmentNumber;
|
|
||||||
internal int m_fragmentTotalCount;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns true if this message has been passed to SendMessage() already
|
/// Returns true if this message has been passed to SendMessage() already
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsSent { get { return m_numSends > 0; } }
|
public bool IsSent { get { return m_wasSent; } }
|
||||||
|
|
||||||
internal NetOutgoingMessage()
|
internal NetOutgoingMessage()
|
||||||
{
|
{
|
||||||
Reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Reset()
|
internal void Reset()
|
||||||
{
|
{
|
||||||
NetException.Assert(m_inQueueCount == 0, "Ouch! Resetting NetOutgoingMessage still in some queue!");
|
NetException.Assert(m_numUnfinishedSendings == 0, "Ouch! Resetting NetOutgoingMessage still in some queue!");
|
||||||
|
NetException.Assert(m_wasSent == true, "Ouch! Resetting unsent message!");
|
||||||
|
|
||||||
m_bitLength = 0;
|
m_bitLength = 0;
|
||||||
m_type = NetMessageType.Error;
|
m_libType = NetMessageLibraryType.Error;
|
||||||
m_inQueueCount = 0;
|
m_wasSent = false;
|
||||||
m_numSends = 0;
|
|
||||||
m_fragmentGroupId = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static int EncodeAcksMessage(byte[] buffer, int ptr, NetConnection conn, int maxBytesPayload)
|
internal static int EncodeAcksMessage(byte[] buffer, int ptr, NetConnection conn, int maxBytesPayload)
|
||||||
@@ -98,27 +90,18 @@ namespace Lidgren.Network
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// encode and store for resending (if conn != null and message is reliable)
|
internal int EncodeUnfragmented(byte[] buffer, int ptr, NetMessageType tp, ushort sequenceNumber)
|
||||||
internal int Encode(double now, byte[] buffer, int ptr, NetConnection conn)
|
|
||||||
{
|
{
|
||||||
// message type
|
// message type
|
||||||
buffer[ptr++] = (byte)((int)m_type | (m_fragmentGroupId == -1 ? 0 : 128));
|
buffer[ptr++] = (byte)tp; // | (m_fragmentGroupId == -1 ? 0 : 128));
|
||||||
|
|
||||||
if (m_type == NetMessageType.Library)
|
if (tp == NetMessageType.Library)
|
||||||
buffer[ptr++] =(byte)m_libType;
|
buffer[ptr++] = (byte)m_libType;
|
||||||
|
|
||||||
// channel sequence number
|
// channel sequence number
|
||||||
if (m_type >= NetMessageType.UserSequenced)
|
if (tp >= NetMessageType.UserSequenced)
|
||||||
{
|
{
|
||||||
if (conn == null)
|
ushort seqNr = (ushort)sequenceNumber;
|
||||||
throw new NetException("Trying to encode NetMessageType " + m_type + " to unconnected endpoint!");
|
|
||||||
|
|
||||||
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;
|
||||||
buffer[ptr++] = (byte)(seqNr >> 8);
|
buffer[ptr++] = (byte)(seqNr >> 8);
|
||||||
}
|
}
|
||||||
@@ -140,17 +123,6 @@ namespace Lidgren.Network
|
|||||||
throw new NetException("Packet content too large; 4095 bytes maximum");
|
throw new NetException("Packet content too large; 4095 bytes maximum");
|
||||||
}
|
}
|
||||||
|
|
||||||
// fragmentation info
|
|
||||||
if (m_fragmentGroupId != -1)
|
|
||||||
{
|
|
||||||
buffer[ptr++] = (byte)m_fragmentGroupId;
|
|
||||||
buffer[ptr++] = (byte)(m_fragmentGroupId >> 8);
|
|
||||||
buffer[ptr++] = (byte)m_fragmentTotalCount;
|
|
||||||
buffer[ptr++] = (byte)(m_fragmentTotalCount >> 8);
|
|
||||||
buffer[ptr++] = (byte)m_fragmentNumber;
|
|
||||||
buffer[ptr++] = (byte)(m_fragmentNumber >> 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
// payload
|
// payload
|
||||||
if (payloadBitsLength > 0)
|
if (payloadBitsLength > 0)
|
||||||
{
|
{
|
||||||
@@ -161,7 +133,62 @@ namespace Lidgren.Network
|
|||||||
ptr += payloadBytesLength;
|
ptr += payloadBytesLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_numSends++;
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal int EncodeFragmented(byte[] buffer, int ptr, NetSending send, int mtu)
|
||||||
|
{
|
||||||
|
NetException.Assert(send.MessageType != NetMessageType.Library, "Library messages cant be fragmented");
|
||||||
|
|
||||||
|
// message type
|
||||||
|
buffer[ptr++] = (byte)((int)send.MessageType | 128);
|
||||||
|
|
||||||
|
// channel sequence number
|
||||||
|
if (send.MessageType >= NetMessageType.UserSequenced)
|
||||||
|
{
|
||||||
|
ushort seqNr = (ushort)send.SequenceNumber;
|
||||||
|
buffer[ptr++] = (byte)seqNr;
|
||||||
|
buffer[ptr++] = (byte)(seqNr >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate fragment payload length
|
||||||
|
mtu -= NetConstants.FragmentHeaderSize; // size of fragmentation info
|
||||||
|
int thisFragmentLength = (send.FragmentNumber == send.FragmentTotalCount - 1 ? (send.Message.LengthBytes - (mtu * (send.FragmentTotalCount - 1))) : mtu);
|
||||||
|
|
||||||
|
int payloadBitsLength = thisFragmentLength * 8;
|
||||||
|
if (payloadBitsLength < 127)
|
||||||
|
{
|
||||||
|
buffer[ptr++] = (byte)payloadBitsLength;
|
||||||
|
}
|
||||||
|
else if (payloadBitsLength < 32768)
|
||||||
|
{
|
||||||
|
buffer[ptr++] = (byte)((payloadBitsLength & 127) | 128);
|
||||||
|
buffer[ptr++] = (byte)(payloadBitsLength >> 7);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NetException("Packet content too large; 4095 bytes maximum");
|
||||||
|
}
|
||||||
|
|
||||||
|
// fragmentation info
|
||||||
|
buffer[ptr++] = (byte)send.FragmentGroupId;
|
||||||
|
buffer[ptr++] = (byte)(send.FragmentGroupId >> 8);
|
||||||
|
buffer[ptr++] = (byte)send.FragmentTotalCount;
|
||||||
|
buffer[ptr++] = (byte)(send.FragmentTotalCount >> 8);
|
||||||
|
buffer[ptr++] = (byte)send.FragmentNumber;
|
||||||
|
buffer[ptr++] = (byte)(send.FragmentNumber >> 8);
|
||||||
|
|
||||||
|
// payload
|
||||||
|
if (payloadBitsLength > 0)
|
||||||
|
{
|
||||||
|
// zero out last byte
|
||||||
|
buffer[ptr + thisFragmentLength] = 0;
|
||||||
|
|
||||||
|
int offset = (mtu * send.FragmentNumber);
|
||||||
|
|
||||||
|
Buffer.BlockCopy(m_data, offset, buffer, ptr, thisFragmentLength);
|
||||||
|
ptr += thisFragmentLength;
|
||||||
|
}
|
||||||
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
@@ -184,18 +211,7 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
StringBuilder bdr = new StringBuilder();
|
return "[NetOutgoingMessage " + LengthBytes + " bytes]";
|
||||||
bdr.Append("[NetOutgoingMessage ");
|
|
||||||
bdr.Append(m_type.ToString());
|
|
||||||
if (m_type == NetMessageType.Library)
|
|
||||||
{
|
|
||||||
bdr.Append('|');
|
|
||||||
bdr.Append(m_libType.ToString());
|
|
||||||
}
|
|
||||||
bdr.Append(" sent ");
|
|
||||||
bdr.Append(m_numSends);
|
|
||||||
bdr.Append(" times]");
|
|
||||||
return bdr.ToString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ namespace Lidgren.Network
|
|||||||
case PendingConnectionStatus.Denied:
|
case PendingConnectionStatus.Denied:
|
||||||
// send disconnected
|
// send disconnected
|
||||||
NetOutgoingMessage bye = CreateLibraryMessage(NetMessageLibraryType.Disconnect, conn.m_pendingDenialReason);
|
NetOutgoingMessage bye = CreateLibraryMessage(NetMessageLibraryType.Disconnect, conn.m_pendingDenialReason);
|
||||||
EnqueueUnconnectedMessage(bye, conn.m_remoteEndpoint);
|
SendUnconnectedLibrary(bye, conn.m_remoteEndpoint);
|
||||||
m_pendingConnections.Remove(conn);
|
m_pendingConnections.Remove(conn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ namespace Lidgren.Network
|
|||||||
public void DiscoverLocalPeers(int serverPort)
|
public void DiscoverLocalPeers(int serverPort)
|
||||||
{
|
{
|
||||||
NetOutgoingMessage om = CreateMessage(0);
|
NetOutgoingMessage om = CreateMessage(0);
|
||||||
SendUnconnectedLibraryMessage(om, NetMessageLibraryType.Discovery, new IPEndPoint(IPAddress.Broadcast, serverPort));
|
om.m_libType = NetMessageLibraryType.Discovery;
|
||||||
|
SendUnconnectedLibrary(om, new IPEndPoint(IPAddress.Broadcast, serverPort));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -31,7 +32,8 @@ namespace Lidgren.Network
|
|||||||
public bool DiscoverKnownPeer(IPEndPoint endpoint)
|
public bool DiscoverKnownPeer(IPEndPoint endpoint)
|
||||||
{
|
{
|
||||||
NetOutgoingMessage om = CreateMessage(0);
|
NetOutgoingMessage om = CreateMessage(0);
|
||||||
SendUnconnectedLibraryMessage(om, NetMessageLibraryType.Discovery, endpoint);
|
om.m_libType = NetMessageLibraryType.Discovery;
|
||||||
|
SendUnconnectedLibrary(om, endpoint);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ namespace Lidgren.Network
|
|||||||
private int m_listenPort;
|
private int m_listenPort;
|
||||||
private AutoResetEvent m_messageReceivedEvent = new AutoResetEvent(false);
|
private AutoResetEvent m_messageReceivedEvent = new AutoResetEvent(false);
|
||||||
|
|
||||||
private readonly NetQueue<NetIncomingMessage> m_releasedIncomingMessages = new NetQueue<NetIncomingMessage>(16);
|
private readonly NetQueue<NetIncomingMessage> m_releasedIncomingMessages = new NetQueue<NetIncomingMessage>(8);
|
||||||
private readonly NetQueue<NetOutgoingMessage> m_unsentUnconnectedMessage = new NetQueue<NetOutgoingMessage>(4);
|
private readonly NetQueue<NetSending> m_unsentUnconnectedMessage = new NetQueue<NetSending>(2);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Signalling event which can be waited on to determine when a message is queued for reading.
|
/// Signalling event which can be waited on to determine when a message is queued for reading.
|
||||||
@@ -115,9 +115,19 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
m_listenPort = boundEp.Port;
|
m_listenPort = boundEp.Port;
|
||||||
|
|
||||||
long first = (pa == null ? (long)this.GetHashCode() : (long)pa.GetHashCode());
|
int first = (pa == null ? this.GetHashCode() : pa.GetHashCode());
|
||||||
long second = (long)((long)boundEp.GetHashCode() << 32);
|
int second = boundEp.GetHashCode();
|
||||||
m_uniqueIdentifier = first ^ second;
|
|
||||||
|
byte[] raw = new byte[8];
|
||||||
|
raw[0] = (byte)first;
|
||||||
|
raw[1] = (byte)(first << 8);
|
||||||
|
raw[2] = (byte)(first << 16);
|
||||||
|
raw[3] = (byte)(first << 24);
|
||||||
|
raw[4] = (byte)second;
|
||||||
|
raw[5] = (byte)(second << 8);
|
||||||
|
raw[6] = (byte)(second << 16);
|
||||||
|
raw[7] = (byte)(second << 24);
|
||||||
|
m_uniqueIdentifier = BitConverter.ToInt64(NetSha.Hash(raw), 0);
|
||||||
|
|
||||||
m_receiveBuffer = new byte[m_configuration.ReceiveBufferSize];
|
m_receiveBuffer = new byte[m_configuration.ReceiveBufferSize];
|
||||||
m_sendBuffer = new byte[m_configuration.SendBufferSize];
|
m_sendBuffer = new byte[m_configuration.SendBufferSize];
|
||||||
@@ -222,25 +232,23 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
|
|
||||||
// send unconnected sends
|
// send unconnected sends
|
||||||
NetOutgoingMessage um;
|
NetSending uncSend;
|
||||||
while ((um = m_unsentUnconnectedMessage.TryDequeue()) != null)
|
while ((uncSend = m_unsentUnconnectedMessage.TryDequeue()) != null)
|
||||||
{
|
{
|
||||||
IPEndPoint recipient = um.m_unconnectedRecipient;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// TODO: use throttling here
|
// TODO: use throttling here
|
||||||
//
|
//
|
||||||
|
|
||||||
int ptr = um.Encode(now, m_sendBuffer, 0, null);
|
int ptr = uncSend.Message.EncodeUnfragmented(m_sendBuffer, 0, uncSend.MessageType, uncSend.SequenceNumber);
|
||||||
bool connectionReset = false;
|
bool connectionReset = false;
|
||||||
|
|
||||||
if (recipient.Address.Equals(IPAddress.Broadcast))
|
if (uncSend.Recipient.Address.Equals(IPAddress.Broadcast))
|
||||||
{
|
{
|
||||||
// send using broadcast
|
// send using broadcast
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
|
m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
|
||||||
SendPacket(ptr, recipient, 1, out connectionReset);
|
SendPacket(ptr, uncSend.Recipient, 1, out connectionReset);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -250,11 +258,16 @@ namespace Lidgren.Network
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// send normally
|
// send normally
|
||||||
SendPacket(ptr, recipient, 1, out connectionReset);
|
SendPacket(ptr, uncSend.Recipient, 1, out connectionReset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connectionReset)
|
if (connectionReset)
|
||||||
LogWarning(NetConstants.ConnResetMessage);
|
LogWarning(NetConstants.ConnResetMessage);
|
||||||
|
|
||||||
|
int unfin = uncSend.Message.m_numUnfinishedSendings;
|
||||||
|
uncSend.Message.m_numUnfinishedSendings = unfin - 1;
|
||||||
|
if (unfin <= 1)
|
||||||
|
Recycle(uncSend.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if we need to reduce the recycled pool
|
// check if we need to reduce the recycled pool
|
||||||
@@ -487,7 +500,7 @@ namespace Lidgren.Network
|
|||||||
LogWarning("Connect received with wrong appidentifier (need '" + m_configuration.AppIdentifier + "' found '" + appIdent + "') from " + senderEndpoint);
|
LogWarning("Connect received with wrong appidentifier (need '" + m_configuration.AppIdentifier + "' found '" + appIdent + "') from " + senderEndpoint);
|
||||||
|
|
||||||
NetOutgoingMessage bye = CreateLibraryMessage(NetMessageLibraryType.Disconnect, "Wrong app identifier!");
|
NetOutgoingMessage bye = CreateLibraryMessage(NetMessageLibraryType.Disconnect, "Wrong app identifier!");
|
||||||
SendUnconnectedLibraryMessage(bye, NetMessageLibraryType.Disconnect, senderEndpoint);
|
SendUnconnectedLibrary(bye, senderEndpoint);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -557,17 +570,30 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
private void HandleServerFull(IPEndPoint connecter)
|
private void HandleServerFull(IPEndPoint connecter)
|
||||||
{
|
{
|
||||||
const string rejectMessage = "Server is full!";
|
const string rejectMessage = "Server is full!"; // TODO: put in configuration
|
||||||
NetOutgoingMessage reply = CreateLibraryMessage(NetMessageLibraryType.Disconnect, rejectMessage);
|
NetOutgoingMessage reply = CreateLibraryMessage(NetMessageLibraryType.Disconnect, rejectMessage);
|
||||||
EnqueueUnconnectedMessage(reply, connecter);
|
SendLibraryImmediately(reply, connecter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// called by user and network thread
|
// called by user and network thread
|
||||||
private void EnqueueUnconnectedMessage(NetOutgoingMessage msg, IPEndPoint recipient)
|
private void EnqueueUnconnectedMessage(NetOutgoingMessage msg, IPEndPoint recipient)
|
||||||
{
|
{
|
||||||
msg.m_unconnectedRecipient = recipient;
|
NetSending send = new NetSending(msg, NetMessageType.UserUnreliable, 0);
|
||||||
Interlocked.Increment(ref msg.m_inQueueCount);
|
send.Recipient = recipient;
|
||||||
m_unsentUnconnectedMessage.Enqueue(msg);
|
|
||||||
|
msg.m_numUnfinishedSendings++;
|
||||||
|
m_unsentUnconnectedMessage.Enqueue(send);
|
||||||
|
}
|
||||||
|
|
||||||
|
// called by user and network thread
|
||||||
|
private void SendUnconnectedLibrary(NetOutgoingMessage msg, IPEndPoint recipient)
|
||||||
|
{
|
||||||
|
msg.m_wasSent = true;
|
||||||
|
NetSending send = new NetSending(msg, NetMessageType.Library, 0);
|
||||||
|
send.Recipient = recipient;
|
||||||
|
|
||||||
|
msg.m_numUnfinishedSendings++;
|
||||||
|
m_unsentUnconnectedMessage.Enqueue(send);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static NetDeliveryMethod GetDeliveryMethod(NetMessageType mtp)
|
internal static NetDeliveryMethod GetDeliveryMethod(NetMessageType mtp)
|
||||||
@@ -583,21 +609,18 @@ namespace Lidgren.Network
|
|||||||
return NetDeliveryMethod.Unreliable;
|
return NetDeliveryMethod.Unreliable;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void SendImmediately(double now, NetConnection conn, NetOutgoingMessage msg)
|
internal void SendLibraryImmediately(NetOutgoingMessage msg, IPEndPoint destination)
|
||||||
{
|
{
|
||||||
NetException.Assert(msg.m_type == NetMessageType.Library, "SendImmediately can only send library (non-reliable) messages");
|
msg.m_wasSent = true;
|
||||||
|
int len = msg.EncodeUnfragmented(m_sendBuffer, 0, NetMessageType.Library, 0);
|
||||||
msg.m_inQueueCount = 1;
|
|
||||||
int len = msg.Encode(now, m_sendBuffer, 0, conn);
|
|
||||||
Interlocked.Decrement(ref msg.m_inQueueCount);
|
|
||||||
|
|
||||||
bool connectionReset;
|
bool connectionReset;
|
||||||
SendPacket(len, conn.m_remoteEndpoint, 1, out connectionReset);
|
SendPacket(len, destination, 1, out connectionReset);
|
||||||
|
|
||||||
|
// TODO: handle connectionReset
|
||||||
|
|
||||||
Recycle(msg);
|
Recycle(msg);
|
||||||
|
|
||||||
if (connectionReset)
|
|
||||||
LogWarning("Connection was reset; remote host is not listening");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,7 +96,6 @@ namespace Lidgren.Network
|
|||||||
internal NetOutgoingMessage CreateLibraryMessage(NetMessageLibraryType tp, string content)
|
internal NetOutgoingMessage CreateLibraryMessage(NetMessageLibraryType tp, string content)
|
||||||
{
|
{
|
||||||
NetOutgoingMessage retval = CreateMessage(1 + (content == null ? 0 : content.Length));
|
NetOutgoingMessage retval = CreateMessage(1 + (content == null ? 0 : content.Length));
|
||||||
retval.m_type = NetMessageType.Library;
|
|
||||||
retval.m_libType = tp;
|
retval.m_libType = tp;
|
||||||
retval.Write((content == null ? "" : content));
|
retval.Write((content == null ? "" : content));
|
||||||
return retval;
|
return retval;
|
||||||
@@ -139,22 +138,20 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
foreach (NetConnection conn in m_connections)
|
foreach (NetConnection conn in m_connections)
|
||||||
{
|
{
|
||||||
if (conn.m_unsentMessages.Contains(msg))
|
for (int i = 0; i < conn.m_unsentMessages.Count; i++)
|
||||||
|
{
|
||||||
|
NetSending send = conn.m_unsentMessages.TryPeek(i);
|
||||||
|
if (send != null && send.Message == msg)
|
||||||
throw new NetException("Ouch! Recycling unsent message!");
|
throw new NetException("Ouch! Recycling unsent message!");
|
||||||
|
|
||||||
for(int i=0;i<conn.m_storedMessages.Length;i++)
|
foreach (NetSending asend in conn.m_unackedSends)
|
||||||
{
|
if (asend.Message == msg)
|
||||||
var dict = conn.m_storedMessages[i];
|
|
||||||
if (dict != null)
|
|
||||||
{
|
|
||||||
if (dict.ContainsValue(msg))
|
|
||||||
throw new NetException("Ouch! Recycling stored message!");
|
throw new NetException("Ouch! Recycling stored message!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
NetException.Assert(msg.m_inQueueCount == 0, "Recycling message still in some queue!");
|
NetException.Assert(msg.m_numUnfinishedSendings == 0, "Recycling m_numUnfinishedSendings is " + msg.m_numUnfinishedSendings + " (expected 0)");
|
||||||
|
|
||||||
if (msg.m_data != null)
|
if (msg.m_data != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -239,35 +239,37 @@ namespace Lidgren.Network
|
|||||||
if (m_status != NetPeerStatus.Running)
|
if (m_status != NetPeerStatus.Running)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
msg.m_type = (NetMessageType)((int)deliveryMethod + channel);
|
return recipient.SendMessage(msg, deliveryMethod, channel);
|
||||||
|
|
||||||
recipient.EnqueueOutgoingMessage(msg);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Send a message to a number of existing connections
|
/// Send a message to a number of existing connections; returns true if all recipients were sent the message
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="channel">Delivery channel (0-31)</param>
|
/// <param name="channel">Delivery channel (0-31)</param>
|
||||||
public bool SendMessage(NetOutgoingMessage msg, IEnumerable<NetConnection> recipients, NetDeliveryMethod deliveryMethod, int channel)
|
public bool SendMessage(NetOutgoingMessage msg, IEnumerable<NetConnection> recipients, NetDeliveryMethod deliveryMethod, int sequenceChannel)
|
||||||
{
|
{
|
||||||
if (msg.IsSent)
|
if (msg.IsSent)
|
||||||
throw new NetException("Message has already been sent!");
|
throw new NetException("Message has already been sent!");
|
||||||
if (channel < 0 || channel > NetConstants.NetChannelsPerDeliveryMethod)
|
if (sequenceChannel < 0 || sequenceChannel > NetConstants.NetChannelsPerDeliveryMethod)
|
||||||
throw new NetException("Channel must be between 0 and " + (NetConstants.NetChannelsPerDeliveryMethod - 1));
|
throw new NetException("Channel must be between 0 and " + (NetConstants.NetChannelsPerDeliveryMethod - 1));
|
||||||
if (channel != 0 && (deliveryMethod == NetDeliveryMethod.Unreliable || deliveryMethod == NetDeliveryMethod.ReliableUnordered))
|
if (sequenceChannel != 0 && (deliveryMethod == NetDeliveryMethod.Unreliable || deliveryMethod == NetDeliveryMethod.ReliableUnordered))
|
||||||
throw new NetException("Channel must be 0 for Unreliable and ReliableUnordered");
|
throw new NetException("Channel must be 0 for Unreliable and ReliableUnordered");
|
||||||
|
|
||||||
if (m_status != NetPeerStatus.Running)
|
if (m_status != NetPeerStatus.Running)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
msg.m_type = (NetMessageType)((int)deliveryMethod + channel);
|
msg.m_wasSent = true;
|
||||||
|
|
||||||
|
NetMessageType tp = (NetMessageType)((int)deliveryMethod + sequenceChannel);
|
||||||
|
|
||||||
|
bool all = true;
|
||||||
foreach (NetConnection conn in recipients)
|
foreach (NetConnection conn in recipients)
|
||||||
conn.EnqueueOutgoingMessage(msg);
|
{
|
||||||
|
if (!conn.EnqueueSendMessage(msg, tp))
|
||||||
|
all = false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return all;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -282,7 +284,6 @@ namespace Lidgren.Network
|
|||||||
if (adr == null)
|
if (adr == null)
|
||||||
throw new NetException("Failed to resolve " + host);
|
throw new NetException("Failed to resolve " + host);
|
||||||
|
|
||||||
msg.m_type = NetMessageType.UserUnreliable; // sortof not applicable
|
|
||||||
EnqueueUnconnectedMessage(msg, new IPEndPoint(adr, port));
|
EnqueueUnconnectedMessage(msg, new IPEndPoint(adr, port));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,16 +294,6 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
if (msg.IsSent)
|
if (msg.IsSent)
|
||||||
throw new NetException("Message has already been sent!");
|
throw new NetException("Message has already been sent!");
|
||||||
msg.m_type = NetMessageType.UserUnreliable; // sortof not applicable
|
|
||||||
EnqueueUnconnectedMessage(msg, recipient);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void SendUnconnectedLibraryMessage(NetOutgoingMessage msg, NetMessageLibraryType libType, IPEndPoint recipient)
|
|
||||||
{
|
|
||||||
if (msg.IsSent)
|
|
||||||
throw new NetException("Message has already been sent!");
|
|
||||||
msg.m_type = NetMessageType.Library;
|
|
||||||
msg.m_libType = libType;
|
|
||||||
EnqueueUnconnectedMessage(msg, recipient);
|
EnqueueUnconnectedMessage(msg, recipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,9 +304,8 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
if (msg.IsSent)
|
if (msg.IsSent)
|
||||||
throw new NetException("Message has already been sent!");
|
throw new NetException("Message has already been sent!");
|
||||||
msg.m_type = NetMessageType.UserUnreliable; // sortof not applicable
|
foreach (IPEndPoint rec in recipients)
|
||||||
foreach (IPEndPoint ipe in recipients)
|
EnqueueUnconnectedMessage(msg, rec);
|
||||||
EnqueueUnconnectedMessage(msg, ipe);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -327,9 +317,9 @@ namespace Lidgren.Network
|
|||||||
msg = CreateMessage(0);
|
msg = CreateMessage(0);
|
||||||
if (msg.IsSent)
|
if (msg.IsSent)
|
||||||
throw new NetException("Message has already been sent!");
|
throw new NetException("Message has already been sent!");
|
||||||
msg.m_type = NetMessageType.Library;
|
|
||||||
msg.m_libType = NetMessageLibraryType.DiscoveryResponse;
|
msg.m_libType = NetMessageLibraryType.DiscoveryResponse;
|
||||||
EnqueueUnconnectedMessage(msg, recipient);
|
SendUnconnectedLibrary(msg, recipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -52,8 +52,6 @@ namespace Lidgren.Network
|
|||||||
internal float m_pingFrequency;
|
internal float m_pingFrequency;
|
||||||
|
|
||||||
// reliability
|
// reliability
|
||||||
internal float[] m_resendRTTMultiplier;
|
|
||||||
internal float[] m_resendBaseTime;
|
|
||||||
internal float m_maxAckDelayTime;
|
internal float m_maxAckDelayTime;
|
||||||
|
|
||||||
// bad network simulation
|
// bad network simulation
|
||||||
@@ -77,7 +75,7 @@ namespace Lidgren.Network
|
|||||||
m_sendBufferSize = 131071;
|
m_sendBufferSize = 131071;
|
||||||
m_keepAliveDelay = 4.0f;
|
m_keepAliveDelay = 4.0f;
|
||||||
m_connectionTimeout = 25;
|
m_connectionTimeout = 25;
|
||||||
m_maximumConnections = 8;
|
m_maximumConnections = 16;
|
||||||
m_defaultOutgoingMessageCapacity = 8;
|
m_defaultOutgoingMessageCapacity = 8;
|
||||||
m_pingFrequency = 6.0f;
|
m_pingFrequency = 6.0f;
|
||||||
m_throttleBytesPerSecond = 1024 * 512;
|
m_throttleBytesPerSecond = 1024 * 512;
|
||||||
@@ -96,37 +94,6 @@ namespace Lidgren.Network
|
|||||||
// default disabled types
|
// default disabled types
|
||||||
m_disabledTypes = NetIncomingMessageType.ConnectionApproval | NetIncomingMessageType.UnconnectedData | NetIncomingMessageType.VerboseDebugMessage;
|
m_disabledTypes = NetIncomingMessageType.ConnectionApproval | NetIncomingMessageType.UnconnectedData | NetIncomingMessageType.VerboseDebugMessage;
|
||||||
|
|
||||||
// reliability
|
|
||||||
m_resendRTTMultiplier = new float[]
|
|
||||||
{
|
|
||||||
1.1f,
|
|
||||||
2.25f,
|
|
||||||
3.5f,
|
|
||||||
4.0f,
|
|
||||||
4.0f,
|
|
||||||
4.0f,
|
|
||||||
4.0f,
|
|
||||||
4.0f,
|
|
||||||
4.0f,
|
|
||||||
6.0f,
|
|
||||||
6.0f
|
|
||||||
};
|
|
||||||
|
|
||||||
m_resendBaseTime = new float[]
|
|
||||||
{
|
|
||||||
0.025f, // just processing time + ack delay wait time
|
|
||||||
0.05f, // just processing time + ack delay wait time
|
|
||||||
0.2f, // 0.16 delay since last resend
|
|
||||||
0.5f, // 0.3 delay
|
|
||||||
1.5f, // 1.0 delay
|
|
||||||
3.0f, // 1.5 delay
|
|
||||||
5.0f, // 2.0 delay
|
|
||||||
7.5f, // 2.5 delay
|
|
||||||
12.5f, // 5.0 delay
|
|
||||||
17.5f, // 5.0 delay
|
|
||||||
25.0f // 7.5 delay, obi wan you're my only hope
|
|
||||||
};
|
|
||||||
|
|
||||||
// Maximum transmission unit
|
// Maximum transmission unit
|
||||||
// The aim is for a max full packet to be 1440 bytes (30 x 48 bytes, lower than 1468)
|
// The aim is for a max full packet to be 1440 bytes (30 x 48 bytes, lower than 1468)
|
||||||
// 20 bytes ip header
|
// 20 bytes ip header
|
||||||
|
|||||||
@@ -63,12 +63,12 @@ namespace Lidgren.Network
|
|||||||
public void Enqueue(T item)
|
public void Enqueue(T item)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (typeof(T) == typeof(NetOutgoingMessage))
|
if (typeof(T) == typeof(NetSending))
|
||||||
{
|
{
|
||||||
NetOutgoingMessage om = item as NetOutgoingMessage;
|
NetSending om = item as NetSending;
|
||||||
if (om != null)
|
if (om != null)
|
||||||
if (om.m_type == NetMessageType.Error)
|
if (om.MessageType == NetMessageType.Error)
|
||||||
throw new NetException("Enqueuing error message!");
|
throw new NetException("Enqueuing NetSending with MessageType.Error!");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
lock (m_lock)
|
lock (m_lock)
|
||||||
@@ -153,6 +153,19 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public T TryPeek(int offset)
|
||||||
|
{
|
||||||
|
if (m_size == 0)
|
||||||
|
return default(T);
|
||||||
|
|
||||||
|
lock (m_lock)
|
||||||
|
{
|
||||||
|
if (m_size == 0)
|
||||||
|
return default(T);
|
||||||
|
return m_items[(m_head + offset) % m_items.Length];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool Contains(T item)
|
public bool Contains(T item)
|
||||||
{
|
{
|
||||||
lock (m_lock)
|
lock (m_lock)
|
||||||
|
|||||||
50
Lidgren.Network/NetSending.cs
Normal file
50
Lidgren.Network/NetSending.cs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace Lidgren.Network
|
||||||
|
{
|
||||||
|
[DebuggerDisplay("MessageType={MessageType} SequenceNumber={SequenceNumber} NumSends={NumSends}")]
|
||||||
|
internal sealed class NetSending
|
||||||
|
{
|
||||||
|
public NetOutgoingMessage Message;
|
||||||
|
public IPEndPoint Recipient;
|
||||||
|
public NetMessageType MessageType;
|
||||||
|
public ushort SequenceNumber;
|
||||||
|
public double NextResend;
|
||||||
|
public int NumSends; // how many times has this sending been sent
|
||||||
|
|
||||||
|
public int FragmentGroupId;
|
||||||
|
public int FragmentNumber;
|
||||||
|
public int FragmentTotalCount;
|
||||||
|
|
||||||
|
public NetSending(NetOutgoingMessage msg, NetMessageType tp, ushort sequenceNumber)
|
||||||
|
{
|
||||||
|
Message = msg;
|
||||||
|
MessageType = tp;
|
||||||
|
SequenceNumber = sequenceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void SetNextResend(NetConnection conn)
|
||||||
|
{
|
||||||
|
float baseDelay;
|
||||||
|
switch(NumSends)
|
||||||
|
{
|
||||||
|
case 0: baseDelay = 0.025f; break;
|
||||||
|
case 1: baseDelay = 0.05f; break;
|
||||||
|
case 2: baseDelay = 0.15f; break;
|
||||||
|
case 3: baseDelay = 0.3f; break;
|
||||||
|
default:
|
||||||
|
baseDelay = (float)(NumSends - 3); // 4: 1 second, 5: 2 seconds, 6: 3 seconds etc
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
float rttMultiplier = 1.15f + (0.15f * NumSends);
|
||||||
|
|
||||||
|
float totalDelay = baseDelay + (conn.AverageRoundtripTime * rttMultiplier);
|
||||||
|
|
||||||
|
NextResend = NetTime.Now + totalDelay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -66,6 +66,8 @@ namespace SamplesCommon
|
|||||||
NetConnection conn = Peer.Connections[0];
|
NetConnection conn = Peer.Connections[0];
|
||||||
bdr.AppendLine("Connection 0:");
|
bdr.AppendLine("Connection 0:");
|
||||||
bdr.AppendLine("Average RTT: " + ((int)(conn.AverageRoundtripTime * 1000.0f)) + " ms");
|
bdr.AppendLine("Average RTT: " + ((int)(conn.AverageRoundtripTime * 1000.0f)) + " ms");
|
||||||
|
bdr.AppendLine("Last response: " + (int)(NetTime.Now - conn.Statistics.LastSendRespondedTo) + "s ago");
|
||||||
|
bdr.AppendLine("Most sends: " + conn.Statistics.MostSends);
|
||||||
bdr.Append(conn.Statistics.ToString());
|
bdr.Append(conn.Statistics.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user