v0.2.2: updated Lidgren, railgun shells can be bought, autorestart server, netstats, tutorial moloch spawning in a wall fix, misc error checks

This commit is contained in:
Regalis
2015-10-18 22:44:30 +03:00
parent aa3882a815
commit 0e5e86e363
85 changed files with 2763 additions and 1866 deletions
+113 -41
View File
@@ -3,12 +3,16 @@ using System.Net;
using System.Threading;
using System.Diagnostics;
#if !__NOIPENDPOINT__
using NetEndPoint = System.Net.IPEndPoint;
#endif
namespace Lidgren.Network
{
/// <summary>
/// Represents a connection to a remote peer
/// </summary>
[DebuggerDisplay("RemoteUniqueIdentifier={RemoteUniqueIdentifier} RemoteEndPoint={remoteEndPoint}")]
[DebuggerDisplay("RemoteUniqueIdentifier={RemoteUniqueIdentifier} RemoteEndPoint={m_remoteEndPoint}")]
public partial class NetConnection
{
private const int m_infrequentEventsSkipFrames = 8; // number of heartbeats to skip checking for infrequent events (ping, timeout etc)
@@ -16,9 +20,10 @@ namespace Lidgren.Network
internal NetPeer m_peer;
internal NetPeerConfiguration m_peerConfiguration;
internal NetConnectionStatus m_status;
internal NetConnectionStatus m_visibleStatus;
internal IPEndPoint m_remoteEndPoint;
internal NetConnectionStatus m_status; // actual status
internal NetConnectionStatus m_outputtedStatus; // status that has been sent as StatusChanged message
internal NetConnectionStatus m_visibleStatus; // status visible by querying the Status property
internal NetEndPoint m_remoteEndPoint;
internal NetSenderChannelBase[] m_sendChannels;
internal NetReceiverChannelBase[] m_receiveChannels;
internal NetOutgoingMessage m_localHailMessage;
@@ -57,7 +62,7 @@ namespace Lidgren.Network
/// <summary>
/// Gets the remote endpoint for the connection
/// </summary>
public IPEndPoint RemoteEndPoint { get { return m_remoteEndPoint; } }
public NetEndPoint RemoteEndPoint { get { return m_remoteEndPoint; } }
/// <summary>
/// Gets the unique identifier of the remote NetPeer for this connection
@@ -70,19 +75,20 @@ namespace Lidgren.Network
public NetOutgoingMessage LocalHailMessage { get { return m_localHailMessage; } }
// gets the time before automatically resending an unacked message
internal float GetResendDelay()
internal double GetResendDelay()
{
float avgRtt = m_averageRoundtripTime;
double avgRtt = m_averageRoundtripTime;
if (avgRtt <= 0)
avgRtt = 0.1f; // "default" resend is based on 100 ms roundtrip time
return 0.02f + (avgRtt * 2.0f); // 20 ms + double rtt
avgRtt = 0.1; // "default" resend is based on 100 ms roundtrip time
return 0.025 + (avgRtt * 2.1); // 25 ms + double rtt
}
internal NetConnection(NetPeer peer, IPEndPoint remoteEndPoint)
internal NetConnection(NetPeer peer, NetEndPoint remoteEndPoint)
{
m_peer = peer;
m_peerConfiguration = m_peer.Configuration;
m_status = NetConnectionStatus.None;
m_outputtedStatus = NetConnectionStatus.None;
m_visibleStatus = NetConnectionStatus.None;
m_remoteEndPoint = remoteEndPoint;
m_sendChannels = new NetSenderChannelBase[NetConstants.NumTotalChannels];
@@ -97,45 +103,52 @@ namespace Lidgren.Network
/// <summary>
/// Change the internal endpoint to this new one. Used when, during handshake, a switch in port is detected (due to NAT)
/// </summary>
internal void MutateEndPoint(IPEndPoint endPoint)
internal void MutateEndPoint(NetEndPoint endPoint)
{
m_remoteEndPoint = endPoint;
}
internal void ResetTimeout(double now)
{
m_timeoutDeadline = now + m_peerConfiguration.m_connectionTimeout;
}
internal void SetStatus(NetConnectionStatus status, string reason)
{
// user or library thread
if (status == m_status)
return;
m_status = status;
if (reason == null)
reason = string.Empty;
if (m_status == NetConnectionStatus.Connected)
{
m_timeoutDeadline = (float)NetTime.Now + m_peerConfiguration.m_connectionTimeout;
m_timeoutDeadline = NetTime.Now + m_peerConfiguration.m_connectionTimeout;
m_peer.LogVerbose("Timeout deadline initialized to " + m_timeoutDeadline);
}
if (m_peerConfiguration.IsMessageTypeEnabled(NetIncomingMessageType.StatusChanged))
{
NetIncomingMessage info = m_peer.CreateIncomingMessage(NetIncomingMessageType.StatusChanged, 4 + reason.Length + (reason.Length > 126 ? 2 : 1));
info.m_senderConnection = this;
info.m_senderEndPoint = m_remoteEndPoint;
info.Write((byte)m_status);
info.Write(reason);
m_peer.ReleaseMessage(info);
if (m_outputtedStatus != status)
{
NetIncomingMessage info = m_peer.CreateIncomingMessage(NetIncomingMessageType.StatusChanged, 4 + reason.Length + (reason.Length > 126 ? 2 : 1));
info.m_senderConnection = this;
info.m_senderEndPoint = m_remoteEndPoint;
info.Write((byte)m_status);
info.Write(reason);
m_peer.ReleaseMessage(info);
m_outputtedStatus = status;
}
}
else
{
// app dont want those messages, update visible status immediately
m_outputtedStatus = m_status;
m_visibleStatus = m_status;
}
}
internal void Heartbeat(float now, uint frameCounter)
internal void Heartbeat(double now, uint frameCounter)
{
m_peer.VerifyNetworkThread();
@@ -150,6 +163,7 @@ namespace Lidgren.Network
//
m_peer.LogVerbose("Connection timed out at " + now + " deadline was " + m_timeoutDeadline);
ExecuteDisconnect("Connection timed out", true);
return;
}
// send ping?
@@ -164,7 +178,7 @@ namespace Lidgren.Network
if (m_disconnectRequested)
{
ExecuteDisconnect(m_disconnectMessage, true);
ExecuteDisconnect(m_disconnectMessage, m_disconnectReqSendBye);
return;
}
}
@@ -233,8 +247,11 @@ namespace Lidgren.Network
{
//m_peer.LogVerbose("Received ack for " + acktp + "#" + seqNr);
NetSenderChannelBase chan = m_sendChannels[(int)incAck.Item1 - 1];
// If we haven't sent a message on this channel there is no reason to ack it
if (chan == null)
chan = CreateSenderChannel(incAck.Item1);
continue;
chan.ReceiveAcknowledge(now, incAck.Item2);
}
}
@@ -249,7 +266,11 @@ namespace Lidgren.Network
var channel = m_sendChannels[i];
NetException.Assert(m_sendBufferWritePtr < 1 || m_sendBufferNumMessages > 0);
if (channel != null)
{
channel.SendQueuedMessages(now);
if (channel.NeedToSendMessages())
m_peer.m_needFlushSendQueue = true; // failed to send all queued sends; likely a full window - need to try again
}
NetException.Assert(m_sendBufferWritePtr < 1 || m_sendBufferNumMessages > 0);
}
}
@@ -275,24 +296,41 @@ namespace Lidgren.Network
m_peer.VerifyNetworkThread();
int sz = om.GetEncodedSize();
if (sz > m_currentMTU)
m_peer.LogWarning("Message larger than MTU! Fragmentation must have failed!");
//if (sz > m_currentMTU)
// m_peer.LogWarning("Message larger than MTU! Fragmentation must have failed!");
bool connReset; // TODO: handle connection reset
// can fit this message together with previously written to buffer?
if (m_sendBufferWritePtr + sz > m_currentMTU)
{
bool connReset; // TODO: handle connection reset
NetException.Assert(m_sendBufferWritePtr > 0 && m_sendBufferNumMessages > 0); // or else the message should have been fragmented earlier
if (m_sendBufferWritePtr > 0 && m_sendBufferNumMessages > 0)
{
// previous message in buffer; send these first
m_peer.SendPacket(m_sendBufferWritePtr, m_remoteEndPoint, m_sendBufferNumMessages, out connReset);
m_statistics.PacketSent(m_sendBufferWritePtr, m_sendBufferNumMessages);
m_sendBufferWritePtr = 0;
m_sendBufferNumMessages = 0;
}
}
// encode it into buffer regardless if it (now) fits within MTU or not
m_sendBufferWritePtr = om.Encode(m_peer.m_sendBuffer, m_sendBufferWritePtr, seqNr);
m_sendBufferNumMessages++;
if (m_sendBufferWritePtr > m_currentMTU)
{
// send immediately; we're already over MTU
m_peer.SendPacket(m_sendBufferWritePtr, m_remoteEndPoint, m_sendBufferNumMessages, out connReset);
m_statistics.PacketSent(m_sendBufferWritePtr, m_sendBufferNumMessages);
m_sendBufferWritePtr = 0;
m_sendBufferNumMessages = 0;
}
m_sendBufferWritePtr = om.Encode(m_peer.m_sendBuffer, m_sendBufferWritePtr, seqNr);
m_sendBufferNumMessages++;
if (m_sendBufferWritePtr > 0)
m_peer.m_needFlushSendQueue = true; // flush in heartbeat
NetException.Assert(m_sendBufferWritePtr > 0, "Encoded zero size message?");
NetException.Assert(m_sendBufferNumMessages > 0);
Interlocked.Decrement(ref om.m_recyclingCount);
}
/// <summary>
@@ -321,12 +359,12 @@ namespace Lidgren.Network
if (chan == null)
chan = CreateSenderChannel(tp);
if (msg.GetEncodedSize() > m_currentMTU)
throw new NetException("Message too large! Fragmentation failure?");
if ((method != NetDeliveryMethod.Unreliable && method != NetDeliveryMethod.UnreliableSequenced) && msg.GetEncodedSize() > m_currentMTU)
m_peer.ThrowOrLog("Reliable message too large! Fragmentation failure?");
var retval = chan.Enqueue(msg);
if (retval == NetSendResult.Sent && m_peerConfiguration.m_autoFlushSendQueue == false)
retval = NetSendResult.Queued; // queued since we're not autoflushing
//if (retval == NetSendResult.Sent && m_peerConfiguration.m_autoFlushSendQueue == false)
// retval = NetSendResult.Queued; // queued since we're not autoflushing
return retval;
}
@@ -347,12 +385,11 @@ namespace Lidgren.Network
}
else
{
switch (method)
{
case NetDeliveryMethod.Unreliable:
case NetDeliveryMethod.UnreliableSequenced:
chan = new NetUnreliableSenderChannel(this, NetUtility.GetWindowSize(method));
chan = new NetUnreliableSenderChannel(this, NetUtility.GetWindowSize(method), method);
break;
case NetDeliveryMethod.ReliableOrdered:
chan = new NetReliableSenderChannel(this, NetUtility.GetWindowSize(method));
@@ -375,13 +412,34 @@ namespace Lidgren.Network
{
m_peer.VerifyNetworkThread();
float now = (float)NetTime.Now;
double now = NetTime.Now;
switch (tp)
{
case NetMessageType.Connect:
m_peer.LogDebug("Received handshake message (" + tp + ") despite connection being in place");
break;
case NetMessageType.ConnectResponse:
// handshake message must have been lost
HandleConnectResponse(now, tp, ptr, payloadLength);
break;
case NetMessageType.ConnectionEstablished:
// do nothing, all's well
break;
case NetMessageType.LibraryError:
m_peer.ThrowOrLog("LibraryError received by ReceivedLibraryMessage; this usually indicates a malformed message");
break;
case NetMessageType.Disconnect:
NetIncomingMessage msg = m_peer.SetupReadHelperMessage(ptr, payloadLength);
ExecuteDisconnect(msg.ReadString(), false);
m_disconnectRequested = true;
m_disconnectMessage = msg.ReadString();
m_disconnectReqSendBye = false;
//ExecuteDisconnect(msg.ReadString(), false);
break;
case NetMessageType.Acknowledge:
for (int i = 0; i < payloadLength; i+=3)
@@ -408,6 +466,11 @@ namespace Lidgren.Network
SendMTUSuccess(payloadLength);
break;
case NetMessageType.ExpandMTUSuccess:
if (m_peer.Configuration.AutoExpandMTU == false)
{
m_peer.LogDebug("Received ExpandMTURequest altho AutoExpandMTU is turned off!");
break;
}
NetIncomingMessage emsg = m_peer.SetupReadHelperMessage(ptr, payloadLength);
int size = emsg.ReadInt32();
HandleExpandMTUSuccess(now, size);
@@ -492,10 +555,19 @@ namespace Lidgren.Network
}
windowSize = chan.WindowSize;
freeWindowSlots = chan.GetAllowedSends() - chan.m_queuedSends.Count;
freeWindowSlots = chan.GetFreeWindowSlots();
return;
}
public bool CanSendImmediately(NetDeliveryMethod method, int sequenceChannel)
{
int channelSlot = (int)method - 1 + sequenceChannel;
var chan = m_sendChannels[channelSlot];
if (chan == null)
return true;
return chan.GetFreeWindowSlots() > 0;
}
internal void Shutdown(string reason)
{
ExecuteDisconnect(reason, true);