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:
@@ -29,7 +29,7 @@
|
|||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<Optimize>true</Optimize>
|
<Optimize>true</Optimize>
|
||||||
<OutputPath>bin\Windows\Release\</OutputPath>
|
<OutputPath>..\Subsurface\bin\Windows\Release\</OutputPath>
|
||||||
<DefineConstants>TRACE;WINDOWS</DefineConstants>
|
<DefineConstants>TRACE;WINDOWS</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
|
|||||||
@@ -542,7 +542,7 @@ namespace Launcher2
|
|||||||
{
|
{
|
||||||
if (e.Error!=null)
|
if (e.Error!=null)
|
||||||
{
|
{
|
||||||
string errorMsg = "Error while downloading: " + e.Error.InnerException.Message;
|
string errorMsg = "Error while downloading: " + e.Error;
|
||||||
|
|
||||||
GUITextBlock textBlock = new GUITextBlock(
|
GUITextBlock textBlock = new GUITextBlock(
|
||||||
new Rectangle(0, 0, 0, 0),
|
new Rectangle(0, 0, 0, 0),
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Lidgren.Network
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Interface for an encryption algorithm
|
|
||||||
/// </summary>
|
|
||||||
public interface INetEncryption
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypt an outgoing message in place
|
|
||||||
/// </summary>
|
|
||||||
bool Encrypt(NetOutgoingMessage msg);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypt an incoming message in place
|
|
||||||
/// </summary>
|
|
||||||
bool Decrypt(NetIncomingMessage msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,172 +1,26 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
/// <summary>
|
public class NetAESEncryption : NetCryptoProviderBase
|
||||||
/// AES encryption
|
|
||||||
/// </summary>
|
|
||||||
public class NetAESEncryption : INetEncryption
|
|
||||||
{
|
{
|
||||||
private readonly byte[] m_key;
|
public NetAESEncryption(NetPeer peer)
|
||||||
private readonly byte[] m_iv;
|
: base(peer, new AesCryptoServiceProvider())
|
||||||
private readonly int m_bitSize;
|
|
||||||
private static readonly List<int> m_keysizes;
|
|
||||||
private static readonly List<int> m_blocksizes;
|
|
||||||
|
|
||||||
static NetAESEncryption()
|
|
||||||
{
|
|
||||||
#if !IOS && !__ANDROID__
|
|
||||||
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
|
|
||||||
List<int> temp = new List<int>();
|
|
||||||
foreach (KeySizes keysize in aes.LegalKeySizes)
|
|
||||||
{
|
|
||||||
for (int i = keysize.MinSize; i <= keysize.MaxSize; i += keysize.SkipSize)
|
|
||||||
{
|
|
||||||
if (!temp.Contains(i))
|
|
||||||
temp.Add(i);
|
|
||||||
if (i == keysize.MaxSize)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_keysizes = temp;
|
|
||||||
temp = new List<int>();
|
|
||||||
foreach (KeySizes keysize in aes.LegalBlockSizes)
|
|
||||||
{
|
|
||||||
for (int i = keysize.MinSize; i <= keysize.MaxSize; i += keysize.SkipSize)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!temp.Contains(i))
|
|
||||||
temp.Add(i);
|
|
||||||
if (i == keysize.MaxSize)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_blocksizes = temp;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// NetAESEncryption constructor
|
|
||||||
/// </summary>
|
|
||||||
public NetAESEncryption(byte[] key, byte[] iv)
|
|
||||||
{
|
|
||||||
if (!m_keysizes.Contains(key.Length * 8))
|
|
||||||
throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", NetUtility.MakeCommaDelimitedList(m_keysizes)));
|
|
||||||
|
|
||||||
if (!m_blocksizes.Contains(iv.Length * 8))
|
|
||||||
throw new NetException(string.Format("Not a valid iv size. (Valid values are: {0})", NetUtility.MakeCommaDelimitedList(m_blocksizes)));
|
|
||||||
|
|
||||||
m_key = key;
|
|
||||||
m_iv = iv;
|
|
||||||
m_bitSize = m_key.Length * 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// NetAESEncryption constructor
|
|
||||||
/// </summary>
|
|
||||||
public NetAESEncryption(string key, int bitsize)
|
|
||||||
{
|
|
||||||
if (!m_keysizes.Contains(bitsize))
|
|
||||||
throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", NetUtility.MakeCommaDelimitedList(m_keysizes)));
|
|
||||||
|
|
||||||
byte[] entropy = Encoding.UTF32.GetBytes(key);
|
|
||||||
// I know hardcoding salts is bad, but in this case I think it is acceptable.
|
|
||||||
HMACSHA512 hmacsha512 = new HMACSHA512(Convert.FromBase64String("i88NEiez3c50bHqr3YGasDc4p8jRrxJAaiRiqixpvp4XNAStP5YNoC2fXnWkURtkha6M8yY901Gj07IRVIRyGL=="));
|
|
||||||
hmacsha512.Initialize();
|
|
||||||
for (int i = 0; i < 1000; i++)
|
|
||||||
{
|
|
||||||
entropy = hmacsha512.ComputeHash(entropy);
|
|
||||||
}
|
|
||||||
int keylen = bitsize / 8;
|
|
||||||
m_key = new byte[keylen];
|
|
||||||
Buffer.BlockCopy(entropy, 0, m_key, 0, keylen);
|
|
||||||
m_iv = new byte[m_blocksizes[0] / 8];
|
|
||||||
|
|
||||||
Buffer.BlockCopy(entropy, entropy.Length - m_iv.Length - 1, m_iv, 0, m_iv.Length);
|
|
||||||
m_bitSize = bitsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// NetAESEncryption constructor
|
|
||||||
/// </summary>
|
|
||||||
public NetAESEncryption(string key)
|
|
||||||
: this(key, m_keysizes[0])
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public NetAESEncryption(NetPeer peer, string key)
|
||||||
/// Encrypt outgoing message
|
: base(peer, new AesCryptoServiceProvider())
|
||||||
/// </summary>
|
|
||||||
public bool Encrypt(NetOutgoingMessage msg)
|
|
||||||
{
|
{
|
||||||
#if !IOS && !__ANDROID__
|
SetKey(key);
|
||||||
try
|
|
||||||
{
|
|
||||||
// nested usings are fun!
|
|
||||||
using (AesCryptoServiceProvider aesCryptoServiceProvider = new AesCryptoServiceProvider { KeySize = m_bitSize, Mode = CipherMode.CBC })
|
|
||||||
{
|
|
||||||
using (ICryptoTransform cryptoTransform = aesCryptoServiceProvider.CreateEncryptor(m_key, m_iv))
|
|
||||||
{
|
|
||||||
using (MemoryStream memoryStream = new MemoryStream())
|
|
||||||
{
|
|
||||||
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write))
|
|
||||||
{
|
|
||||||
cryptoStream.Write(msg.m_data, 0, msg.m_data.Length);
|
|
||||||
}
|
|
||||||
msg.m_data = memoryStream.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public NetAESEncryption(NetPeer peer, byte[] data, int offset, int count)
|
||||||
/// Decrypt incoming message
|
: base(peer, new AesCryptoServiceProvider())
|
||||||
/// </summary>
|
|
||||||
public bool Decrypt(NetIncomingMessage msg)
|
|
||||||
{
|
{
|
||||||
#if !IOS && !__ANDROID__
|
SetKey(data, offset, count);
|
||||||
try
|
|
||||||
{
|
|
||||||
// nested usings are fun!
|
|
||||||
using (AesCryptoServiceProvider aesCryptoServiceProvider = new AesCryptoServiceProvider { KeySize = m_bitSize, Mode = CipherMode.CBC })
|
|
||||||
{
|
|
||||||
using (ICryptoTransform cryptoTransform = aesCryptoServiceProvider.CreateDecryptor(m_key, m_iv))
|
|
||||||
{
|
|
||||||
using (MemoryStream memoryStream = new MemoryStream())
|
|
||||||
{
|
|
||||||
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform,
|
|
||||||
CryptoStreamMode.Write))
|
|
||||||
{
|
|
||||||
cryptoStream.Write(msg.m_data, 0, msg.m_data.Length);
|
|
||||||
}
|
|
||||||
msg.m_data = memoryStream.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base for a non-threadsafe encryption class
|
/// Base for a non-threadsafe encryption class
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class NetBlockEncryptionBase : INetEncryption
|
public abstract class NetBlockEncryptionBase : NetEncryption
|
||||||
{
|
{
|
||||||
// temporary space for one block to avoid reallocating every time
|
// temporary space for one block to avoid reallocating every time
|
||||||
private byte[] m_tmp;
|
private byte[] m_tmp;
|
||||||
@@ -19,7 +19,8 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// NetBlockEncryptionBase constructor
|
/// NetBlockEncryptionBase constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NetBlockEncryptionBase()
|
public NetBlockEncryptionBase(NetPeer peer)
|
||||||
|
: base(peer)
|
||||||
{
|
{
|
||||||
m_tmp = new byte[BlockSize];
|
m_tmp = new byte[BlockSize];
|
||||||
}
|
}
|
||||||
@@ -27,7 +28,7 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Encrypt am outgoing message with this algorithm; no writing can be done to the message after encryption, or message will be corrupted
|
/// Encrypt am outgoing message with this algorithm; no writing can be done to the message after encryption, or message will be corrupted
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Encrypt(NetOutgoingMessage msg)
|
public override bool Encrypt(NetOutgoingMessage msg)
|
||||||
{
|
{
|
||||||
int payloadBitLength = msg.LengthBits;
|
int payloadBitLength = msg.LengthBits;
|
||||||
int numBytes = msg.LengthBytes;
|
int numBytes = msg.LengthBytes;
|
||||||
@@ -55,7 +56,7 @@ namespace Lidgren.Network
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="msg">message to decrypt</param>
|
/// <param name="msg">message to decrypt</param>
|
||||||
/// <returns>true if successful; false if failed</returns>
|
/// <returns>true if successful; false if failed</returns>
|
||||||
public bool Decrypt(NetIncomingMessage msg)
|
public override bool Decrypt(NetIncomingMessage msg)
|
||||||
{
|
{
|
||||||
int numEncryptedBytes = msg.LengthBytes - 4; // last 4 bytes is true bit length
|
int numEncryptedBytes = msg.LengthBytes - 4; // last 4 bytes is true bit length
|
||||||
int blockSize = BlockSize;
|
int blockSize = BlockSize;
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace Lidgren.Network
|
||||||
|
{
|
||||||
|
public abstract class NetCryptoProviderBase : NetEncryption
|
||||||
|
{
|
||||||
|
protected SymmetricAlgorithm m_algorithm;
|
||||||
|
|
||||||
|
public NetCryptoProviderBase(NetPeer peer, SymmetricAlgorithm algo)
|
||||||
|
: base(peer)
|
||||||
|
{
|
||||||
|
m_algorithm = algo;
|
||||||
|
m_algorithm.GenerateKey();
|
||||||
|
m_algorithm.GenerateIV();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetKey(byte[] data, int offset, int count)
|
||||||
|
{
|
||||||
|
int len = m_algorithm.Key.Length;
|
||||||
|
var key = new byte[len];
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
key[i] = data[offset + (i % count)];
|
||||||
|
m_algorithm.Key = key;
|
||||||
|
|
||||||
|
len = m_algorithm.IV.Length;
|
||||||
|
key = new byte[len];
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
key[len - 1 - i] = data[offset + (i % count)];
|
||||||
|
m_algorithm.IV = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Encrypt(NetOutgoingMessage msg)
|
||||||
|
{
|
||||||
|
int unEncLenBits = msg.LengthBits;
|
||||||
|
|
||||||
|
var ms = new MemoryStream();
|
||||||
|
var cs = new CryptoStream(ms, m_algorithm.CreateEncryptor(), CryptoStreamMode.Write);
|
||||||
|
cs.Write(msg.m_data, 0, msg.LengthBytes);
|
||||||
|
cs.Close();
|
||||||
|
|
||||||
|
// get results
|
||||||
|
var arr = ms.ToArray();
|
||||||
|
ms.Close();
|
||||||
|
|
||||||
|
msg.EnsureBufferSize((arr.Length + 4) * 8);
|
||||||
|
msg.LengthBits = 0; // reset write pointer
|
||||||
|
msg.Write((uint)unEncLenBits);
|
||||||
|
msg.Write(arr);
|
||||||
|
msg.LengthBits = (arr.Length + 4) * 8;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Decrypt(NetIncomingMessage msg)
|
||||||
|
{
|
||||||
|
int unEncLenBits = (int)msg.ReadUInt32();
|
||||||
|
|
||||||
|
var ms = new MemoryStream(msg.m_data, 4, msg.LengthBytes - 4);
|
||||||
|
var cs = new CryptoStream(ms, m_algorithm.CreateDecryptor(), CryptoStreamMode.Read);
|
||||||
|
|
||||||
|
var byteLen = NetUtility.BytesToHoldBits(unEncLenBits);
|
||||||
|
var result = m_peer.GetStorage(byteLen);
|
||||||
|
cs.Read(result, 0, byteLen);
|
||||||
|
cs.Close();
|
||||||
|
|
||||||
|
// TODO: recycle existing msg
|
||||||
|
|
||||||
|
msg.m_data = result;
|
||||||
|
msg.m_bitLength = unEncLenBits;
|
||||||
|
msg.m_readPosition = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace Lidgren.Network
|
||||||
|
{
|
||||||
|
public abstract class NetCryptoProviderEncryption : NetEncryption
|
||||||
|
{
|
||||||
|
public NetCryptoProviderEncryption(NetPeer peer)
|
||||||
|
: base(peer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract CryptoStream GetEncryptStream(MemoryStream ms);
|
||||||
|
|
||||||
|
protected abstract CryptoStream GetDecryptStream(MemoryStream ms);
|
||||||
|
|
||||||
|
public override bool Encrypt(NetOutgoingMessage msg)
|
||||||
|
{
|
||||||
|
int unEncLenBits = msg.LengthBits;
|
||||||
|
|
||||||
|
var ms = new MemoryStream();
|
||||||
|
var cs = GetEncryptStream(ms);
|
||||||
|
cs.Write(msg.m_data, 0, msg.LengthBytes);
|
||||||
|
cs.Close();
|
||||||
|
|
||||||
|
// get results
|
||||||
|
var arr = ms.ToArray();
|
||||||
|
ms.Close();
|
||||||
|
|
||||||
|
msg.EnsureBufferSize((arr.Length + 4) * 8);
|
||||||
|
msg.LengthBits = 0; // reset write pointer
|
||||||
|
msg.Write((uint)unEncLenBits);
|
||||||
|
msg.Write(arr);
|
||||||
|
msg.LengthBits = (arr.Length + 4) * 8;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Decrypt(NetIncomingMessage msg)
|
||||||
|
{
|
||||||
|
int unEncLenBits = (int)msg.ReadUInt32();
|
||||||
|
|
||||||
|
var ms = new MemoryStream(msg.m_data, 4, msg.LengthBytes - 4);
|
||||||
|
var cs = GetDecryptStream(ms);
|
||||||
|
|
||||||
|
var result = m_peer.GetStorage(unEncLenBits);
|
||||||
|
cs.Read(result, 0, NetUtility.BytesToHoldBits(unEncLenBits));
|
||||||
|
cs.Close();
|
||||||
|
|
||||||
|
// TODO: recycle existing msg
|
||||||
|
|
||||||
|
msg.m_data = result;
|
||||||
|
msg.m_bitLength = unEncLenBits;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,164 +1,26 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
/// <summary>
|
public class NetDESEncryption : NetCryptoProviderBase
|
||||||
/// DES encryption
|
|
||||||
/// </summary>
|
|
||||||
public class NetDESEncryption : INetEncryption
|
|
||||||
{
|
{
|
||||||
private readonly byte[] m_key;
|
public NetDESEncryption(NetPeer peer)
|
||||||
private readonly byte[] m_iv;
|
: base(peer, new DESCryptoServiceProvider())
|
||||||
private readonly int m_bitSize;
|
|
||||||
private static readonly List<int> m_keysizes;
|
|
||||||
private static readonly List<int> m_blocksizes;
|
|
||||||
|
|
||||||
static NetDESEncryption()
|
|
||||||
{
|
|
||||||
|
|
||||||
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
|
|
||||||
List<int> temp = new List<int>();
|
|
||||||
foreach (KeySizes keysize in des.LegalKeySizes)
|
|
||||||
{
|
|
||||||
for (int i = keysize.MinSize; i <= keysize.MaxSize; i += keysize.SkipSize)
|
|
||||||
{
|
|
||||||
if (!temp.Contains(i))
|
|
||||||
temp.Add(i);
|
|
||||||
if (i == keysize.MaxSize)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_keysizes = temp;
|
|
||||||
temp = new List<int>();
|
|
||||||
foreach (KeySizes keysize in des.LegalBlockSizes)
|
|
||||||
{
|
|
||||||
for (int i = keysize.MinSize; i <= keysize.MaxSize; i += keysize.SkipSize)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!temp.Contains(i))
|
|
||||||
temp.Add(i);
|
|
||||||
if (i == keysize.MaxSize)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_blocksizes = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// NetDESEncryption constructor
|
|
||||||
/// </summary>
|
|
||||||
public NetDESEncryption(byte[] key, byte[] iv)
|
|
||||||
{
|
|
||||||
if (!m_keysizes.Contains(key.Length * 8))
|
|
||||||
throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", NetUtility.MakeCommaDelimitedList(m_keysizes)));
|
|
||||||
|
|
||||||
if (!m_blocksizes.Contains(iv.Length * 8))
|
|
||||||
throw new NetException(string.Format("Not a valid iv size. (Valid values are: {0})", NetUtility.MakeCommaDelimitedList(m_blocksizes)));
|
|
||||||
|
|
||||||
m_key = key;
|
|
||||||
m_iv = iv;
|
|
||||||
m_bitSize = m_key.Length * 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// NetDESEncryption constructor
|
|
||||||
/// </summary>
|
|
||||||
public NetDESEncryption(string key, int bitsize)
|
|
||||||
{
|
|
||||||
if (!m_keysizes.Contains(bitsize))
|
|
||||||
throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", NetUtility.MakeCommaDelimitedList(m_keysizes)));
|
|
||||||
|
|
||||||
byte[] entropy = Encoding.UTF32.GetBytes(key);
|
|
||||||
// I know hardcoding salts is bad, but in this case I think it is acceptable.
|
|
||||||
HMACSHA512 hmacsha512 = new HMACSHA512(Convert.FromBase64String("i88NEiez3c50bHqr3YGasDc4p8jRrxJAaiRiqixpvp4XNAStP5YNoC2fXnWkURtkha6M8yY901Gj07IRVIRyGL=="));
|
|
||||||
hmacsha512.Initialize();
|
|
||||||
for (int i = 0; i < 1000; i++)
|
|
||||||
{
|
|
||||||
entropy = hmacsha512.ComputeHash(entropy);
|
|
||||||
}
|
|
||||||
int keylen = bitsize / 8;
|
|
||||||
m_key = new byte[keylen];
|
|
||||||
Buffer.BlockCopy(entropy, 0, m_key, 0, keylen);
|
|
||||||
m_iv = new byte[m_blocksizes[0] / 8];
|
|
||||||
|
|
||||||
Buffer.BlockCopy(entropy, entropy.Length - m_iv.Length - 1, m_iv, 0, m_iv.Length);
|
|
||||||
m_bitSize = bitsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// NetDESEncryption constructor
|
|
||||||
/// </summary>
|
|
||||||
public NetDESEncryption(string key)
|
|
||||||
: this(key, m_keysizes[0])
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public NetDESEncryption(NetPeer peer, string key)
|
||||||
/// Encrypt outgoing message
|
: base(peer, new DESCryptoServiceProvider())
|
||||||
/// </summary>
|
|
||||||
public bool Encrypt(NetOutgoingMessage msg)
|
|
||||||
{
|
{
|
||||||
try
|
SetKey(key);
|
||||||
{
|
|
||||||
// nested usings are fun!
|
|
||||||
using (DESCryptoServiceProvider desCryptoServiceProvider = new DESCryptoServiceProvider { KeySize = m_bitSize, Mode = CipherMode.CBC })
|
|
||||||
{
|
|
||||||
using (ICryptoTransform cryptoTransform = desCryptoServiceProvider.CreateEncryptor(m_key, m_iv))
|
|
||||||
{
|
|
||||||
using (MemoryStream memoryStream = new MemoryStream())
|
|
||||||
{
|
|
||||||
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform,
|
|
||||||
CryptoStreamMode.Write))
|
|
||||||
{
|
|
||||||
cryptoStream.Write(msg.m_data, 0, msg.m_data.Length);
|
|
||||||
}
|
|
||||||
msg.m_data = memoryStream.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public NetDESEncryption(NetPeer peer, byte[] data, int offset, int count)
|
||||||
/// Decrypt incoming message
|
: base(peer, new DESCryptoServiceProvider())
|
||||||
/// </summary>
|
|
||||||
public bool Decrypt(NetIncomingMessage msg)
|
|
||||||
{
|
{
|
||||||
try
|
SetKey(data, offset, count);
|
||||||
{
|
|
||||||
// nested usings are fun!
|
|
||||||
using (DESCryptoServiceProvider desCryptoServiceProvider = new DESCryptoServiceProvider { KeySize = m_bitSize, Mode = CipherMode.CBC })
|
|
||||||
{
|
|
||||||
using (ICryptoTransform cryptoTransform = desCryptoServiceProvider.CreateDecryptor(m_key, m_iv))
|
|
||||||
{
|
|
||||||
using (MemoryStream memoryStream = new MemoryStream())
|
|
||||||
{
|
|
||||||
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform,
|
|
||||||
CryptoStreamMode.Write))
|
|
||||||
{
|
|
||||||
cryptoStream.Write(msg.m_data, 0, msg.m_data.Length);
|
|
||||||
}
|
|
||||||
msg.m_data = memoryStream.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace Lidgren.Network
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for an encryption algorithm
|
||||||
|
/// </summary>
|
||||||
|
public abstract class NetEncryption
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// NetPeer
|
||||||
|
/// </summary>
|
||||||
|
protected NetPeer m_peer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor
|
||||||
|
/// </summary>
|
||||||
|
public NetEncryption(NetPeer peer)
|
||||||
|
{
|
||||||
|
if (peer == null)
|
||||||
|
throw new NetException("Peer must not be null");
|
||||||
|
m_peer = peer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetKey(string str)
|
||||||
|
{
|
||||||
|
var bytes = System.Text.Encoding.ASCII.GetBytes(str);
|
||||||
|
SetKey(bytes, 0, bytes.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void SetKey(byte[] data, int offset, int count);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encrypt an outgoing message in place
|
||||||
|
/// </summary>
|
||||||
|
public abstract bool Encrypt(NetOutgoingMessage msg);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decrypt an incoming message in place
|
||||||
|
/// </summary>
|
||||||
|
public abstract bool Decrypt(NetIncomingMessage msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,165 +1,26 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
/// <summary>
|
public class NetRC2Encryption : NetCryptoProviderBase
|
||||||
/// RC2 encryption
|
|
||||||
/// </summary>
|
|
||||||
public class NetRC2Encryption : INetEncryption
|
|
||||||
{
|
{
|
||||||
private readonly byte[] m_key;
|
public NetRC2Encryption(NetPeer peer)
|
||||||
private readonly byte[] m_iv;
|
: base(peer, new RC2CryptoServiceProvider())
|
||||||
private readonly int m_bitSize;
|
|
||||||
private static readonly List<int> m_keysizes;
|
|
||||||
private static readonly List<int> m_blocksizes;
|
|
||||||
|
|
||||||
static NetRC2Encryption()
|
|
||||||
{
|
|
||||||
|
|
||||||
RC2CryptoServiceProvider rc2 = new RC2CryptoServiceProvider();
|
|
||||||
List<int> temp = new List<int>();
|
|
||||||
foreach (KeySizes keysize in rc2.LegalKeySizes)
|
|
||||||
{
|
|
||||||
for (int i = keysize.MinSize; i <= keysize.MaxSize; i += keysize.SkipSize)
|
|
||||||
{
|
|
||||||
if (!temp.Contains(i))
|
|
||||||
temp.Add(i);
|
|
||||||
if (i == keysize.MaxSize)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_keysizes = temp;
|
|
||||||
temp = new List<int>();
|
|
||||||
foreach (KeySizes keysize in rc2.LegalBlockSizes)
|
|
||||||
{
|
|
||||||
for (int i = keysize.MinSize; i <= keysize.MaxSize; i += keysize.SkipSize)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!temp.Contains(i))
|
|
||||||
temp.Add(i);
|
|
||||||
if (i == keysize.MaxSize)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_blocksizes = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// NetRC2Encryption constructor
|
|
||||||
/// </summary>
|
|
||||||
public NetRC2Encryption(byte[] key, byte[] iv)
|
|
||||||
{
|
|
||||||
if (!m_keysizes.Contains(key.Length * 8))
|
|
||||||
throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", NetUtility.MakeCommaDelimitedList(m_keysizes)));
|
|
||||||
|
|
||||||
if (!m_blocksizes.Contains(iv.Length * 8))
|
|
||||||
throw new NetException(string.Format("Not a valid iv size. (Valid values are: {0})", NetUtility.MakeCommaDelimitedList(m_blocksizes)));
|
|
||||||
|
|
||||||
m_key = key;
|
|
||||||
m_iv = iv;
|
|
||||||
m_bitSize = m_key.Length * 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// NetRC2Encryption constructor
|
|
||||||
/// </summary>
|
|
||||||
public NetRC2Encryption(string key, int bitsize)
|
|
||||||
{
|
|
||||||
if (!m_keysizes.Contains(bitsize))
|
|
||||||
throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", NetUtility.MakeCommaDelimitedList(m_keysizes)));
|
|
||||||
|
|
||||||
byte[] entropy = Encoding.UTF32.GetBytes(key);
|
|
||||||
// I know hardcoding salts is bad, but in this case I think it is acceptable.
|
|
||||||
HMACSHA512 hmacsha512 = new HMACSHA512(Convert.FromBase64String("i88NEiez3c50bHqr3YGasDc4p8jRrxJAaiRiqixpvp4XNAStP5YNoC2fXnWkURtkha6M8yY901Gj07IRVIRyGL=="));
|
|
||||||
hmacsha512.Initialize();
|
|
||||||
for (int i = 0; i < 1000; i++)
|
|
||||||
{
|
|
||||||
entropy = hmacsha512.ComputeHash(entropy);
|
|
||||||
}
|
|
||||||
int keylen = bitsize / 8;
|
|
||||||
m_key = new byte[keylen];
|
|
||||||
Buffer.BlockCopy(entropy, 0, m_key, 0, keylen);
|
|
||||||
m_iv = new byte[m_blocksizes[0] / 8];
|
|
||||||
|
|
||||||
Buffer.BlockCopy(entropy, entropy.Length - m_iv.Length - 1, m_iv, 0, m_iv.Length);
|
|
||||||
m_bitSize = bitsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// NetRC2Encryption constructor
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key"></param>
|
|
||||||
public NetRC2Encryption(string key)
|
|
||||||
: this(key, m_keysizes[0])
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public NetRC2Encryption(NetPeer peer, string key)
|
||||||
/// Encrypt outgoing message
|
: base(peer, new RC2CryptoServiceProvider())
|
||||||
/// </summary>
|
|
||||||
public bool Encrypt(NetOutgoingMessage msg)
|
|
||||||
{
|
{
|
||||||
try
|
SetKey(key);
|
||||||
{
|
|
||||||
// nested usings are fun!
|
|
||||||
using (RC2CryptoServiceProvider rc2CryptoServiceProvider = new RC2CryptoServiceProvider { KeySize = m_bitSize, Mode = CipherMode.CBC })
|
|
||||||
{
|
|
||||||
using (ICryptoTransform cryptoTransform = rc2CryptoServiceProvider.CreateEncryptor(m_key, m_iv))
|
|
||||||
{
|
|
||||||
using (MemoryStream memoryStream = new MemoryStream())
|
|
||||||
{
|
|
||||||
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform,
|
|
||||||
CryptoStreamMode.Write))
|
|
||||||
{
|
|
||||||
cryptoStream.Write(msg.m_data, 0, msg.m_data.Length);
|
|
||||||
}
|
|
||||||
msg.m_data = memoryStream.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public NetRC2Encryption(NetPeer peer, byte[] data, int offset, int count)
|
||||||
/// Decrypt incoming message
|
: base(peer, new RC2CryptoServiceProvider())
|
||||||
/// </summary>
|
|
||||||
public bool Decrypt(NetIncomingMessage msg)
|
|
||||||
{
|
{
|
||||||
try
|
SetKey(data, offset, count);
|
||||||
{
|
|
||||||
// nested usings are fun!
|
|
||||||
using (RC2CryptoServiceProvider rc2CryptoServiceProvider = new RC2CryptoServiceProvider { KeySize = m_bitSize, Mode = CipherMode.CBC })
|
|
||||||
{
|
|
||||||
using (ICryptoTransform cryptoTransform = rc2CryptoServiceProvider.CreateDecryptor(m_key, m_iv))
|
|
||||||
{
|
|
||||||
using (MemoryStream memoryStream = new MemoryStream())
|
|
||||||
{
|
|
||||||
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform,
|
|
||||||
CryptoStreamMode.Write))
|
|
||||||
{
|
|
||||||
cryptoStream.Write(msg.m_data, 0, msg.m_data.Length);
|
|
||||||
}
|
|
||||||
msg.m_data = memoryStream.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,164 +1,26 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
/// <summary>
|
public class NetTripleDESEncryption : NetCryptoProviderBase
|
||||||
/// Triple DES encryption
|
|
||||||
/// </summary>
|
|
||||||
public class NetTripleDESEncryption : INetEncryption
|
|
||||||
{
|
{
|
||||||
private readonly byte[] m_key;
|
public NetTripleDESEncryption(NetPeer peer)
|
||||||
private readonly byte[] m_iv;
|
: base(peer, new TripleDESCryptoServiceProvider())
|
||||||
private readonly int m_bitSize;
|
|
||||||
private static readonly List<int> m_keysizes;
|
|
||||||
private static readonly List<int> m_blocksizes;
|
|
||||||
|
|
||||||
static NetTripleDESEncryption()
|
|
||||||
{
|
|
||||||
|
|
||||||
TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider();
|
|
||||||
List<int> temp = new List<int>();
|
|
||||||
foreach (KeySizes keysize in tripleDES.LegalKeySizes)
|
|
||||||
{
|
|
||||||
for (int i = keysize.MinSize; i <= keysize.MaxSize; i += keysize.SkipSize)
|
|
||||||
{
|
|
||||||
if (!temp.Contains(i))
|
|
||||||
temp.Add(i);
|
|
||||||
if (i == keysize.MaxSize)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_keysizes = temp;
|
|
||||||
temp = new List<int>();
|
|
||||||
foreach (KeySizes keysize in tripleDES.LegalBlockSizes)
|
|
||||||
{
|
|
||||||
for (int i = keysize.MinSize; i <= keysize.MaxSize; i += keysize.SkipSize)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!temp.Contains(i))
|
|
||||||
temp.Add(i);
|
|
||||||
if (i == keysize.MaxSize)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_blocksizes = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// NetTriplsDESEncryption constructor
|
|
||||||
/// </summary>
|
|
||||||
public NetTripleDESEncryption(byte[] key, byte[] iv)
|
|
||||||
{
|
|
||||||
if (!m_keysizes.Contains(key.Length * 8))
|
|
||||||
throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", NetUtility.MakeCommaDelimitedList(m_keysizes)));
|
|
||||||
|
|
||||||
if (!m_blocksizes.Contains(iv.Length * 8))
|
|
||||||
throw new NetException(string.Format("Not a valid iv size. (Valid values are: {0})", NetUtility.MakeCommaDelimitedList(m_blocksizes)));
|
|
||||||
|
|
||||||
m_key = key;
|
|
||||||
m_iv = iv;
|
|
||||||
m_bitSize = m_key.Length * 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// NetTriplsDESEncryption constructor
|
|
||||||
/// </summary>
|
|
||||||
public NetTripleDESEncryption(string key, int bitsize)
|
|
||||||
{
|
|
||||||
if (!m_keysizes.Contains(bitsize))
|
|
||||||
throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", NetUtility.MakeCommaDelimitedList(m_keysizes)));
|
|
||||||
|
|
||||||
byte[] entropy = Encoding.UTF32.GetBytes(key);
|
|
||||||
// I know hardcoding salts is bad, but in this case I think it is acceptable.
|
|
||||||
HMACSHA512 hmacsha512 = new HMACSHA512(Convert.FromBase64String("i88NEiez3c50bHqr3YGasDc4p8jRrxJAaiRiqixpvp4XNAStP5YNoC2fXnWkURtkha6M8yY901Gj07IRVIRyGL=="));
|
|
||||||
hmacsha512.Initialize();
|
|
||||||
for (int i = 0; i < 1000; i++)
|
|
||||||
{
|
|
||||||
entropy = hmacsha512.ComputeHash(entropy);
|
|
||||||
}
|
|
||||||
int keylen = bitsize / 8;
|
|
||||||
m_key = new byte[keylen];
|
|
||||||
Buffer.BlockCopy(entropy, 0, m_key, 0, keylen);
|
|
||||||
m_iv = new byte[m_blocksizes[0] / 8];
|
|
||||||
|
|
||||||
Buffer.BlockCopy(entropy, entropy.Length - m_iv.Length - 1, m_iv, 0, m_iv.Length);
|
|
||||||
m_bitSize = bitsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// NetTriplsDESEncryption constructor
|
|
||||||
/// </summary>
|
|
||||||
public NetTripleDESEncryption(string key)
|
|
||||||
: this(key, m_keysizes[0])
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public NetTripleDESEncryption(NetPeer peer, string key)
|
||||||
/// Encrypt outgoing message
|
: base(peer, new TripleDESCryptoServiceProvider())
|
||||||
/// </summary>
|
|
||||||
public bool Encrypt(NetOutgoingMessage msg)
|
|
||||||
{
|
{
|
||||||
try
|
SetKey(key);
|
||||||
{
|
|
||||||
// nested usings are fun!
|
|
||||||
using (TripleDESCryptoServiceProvider tripleDESCryptoServiceProvider = new TripleDESCryptoServiceProvider { KeySize = m_bitSize, Mode = CipherMode.CBC })
|
|
||||||
{
|
|
||||||
using (ICryptoTransform cryptoTransform = tripleDESCryptoServiceProvider.CreateEncryptor(m_key, m_iv))
|
|
||||||
{
|
|
||||||
using (MemoryStream memoryStream = new MemoryStream())
|
|
||||||
{
|
|
||||||
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform,
|
|
||||||
CryptoStreamMode.Write))
|
|
||||||
{
|
|
||||||
cryptoStream.Write(msg.m_data, 0, msg.m_data.Length);
|
|
||||||
}
|
|
||||||
msg.m_data = memoryStream.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public NetTripleDESEncryption(NetPeer peer, byte[] data, int offset, int count)
|
||||||
/// Decrypt incoming message
|
: base(peer, new TripleDESCryptoServiceProvider())
|
||||||
/// </summary>
|
|
||||||
public bool Decrypt(NetIncomingMessage msg)
|
|
||||||
{
|
{
|
||||||
try
|
SetKey(data, offset, count);
|
||||||
{
|
|
||||||
// nested usings are fun!
|
|
||||||
using (TripleDESCryptoServiceProvider tripleDESCryptoServiceProvider = new TripleDESCryptoServiceProvider { KeySize = m_bitSize, Mode = CipherMode.CBC })
|
|
||||||
{
|
|
||||||
using (ICryptoTransform cryptoTransform = tripleDESCryptoServiceProvider.CreateDecryptor(m_key, m_iv))
|
|
||||||
{
|
|
||||||
using (MemoryStream memoryStream = new MemoryStream())
|
|
||||||
{
|
|
||||||
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform,
|
|
||||||
CryptoStreamMode.Write))
|
|
||||||
{
|
|
||||||
cryptoStream.Write(msg.m_data, 0, msg.m_data.Length);
|
|
||||||
}
|
|
||||||
msg.m_data = memoryStream.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,22 +7,30 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Example class; not very good encryption
|
/// Example class; not very good encryption
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class NetXorEncryption : INetEncryption
|
public class NetXorEncryption : NetEncryption
|
||||||
{
|
{
|
||||||
private byte[] m_key;
|
private byte[] m_key;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// NetXorEncryption constructor
|
/// NetXorEncryption constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NetXorEncryption(byte[] key)
|
public NetXorEncryption(NetPeer peer, byte[] key)
|
||||||
|
: base(peer)
|
||||||
{
|
{
|
||||||
m_key = key;
|
m_key = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void SetKey(byte[] data, int offset, int count)
|
||||||
|
{
|
||||||
|
m_key = new byte[count];
|
||||||
|
Array.Copy(data, offset, m_key, 0, count);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// NetXorEncryption constructor
|
/// NetXorEncryption constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NetXorEncryption(string key)
|
public NetXorEncryption(NetPeer peer, string key)
|
||||||
|
: base(peer)
|
||||||
{
|
{
|
||||||
m_key = Encoding.UTF8.GetBytes(key);
|
m_key = Encoding.UTF8.GetBytes(key);
|
||||||
}
|
}
|
||||||
@@ -30,7 +38,7 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Encrypt an outgoing message
|
/// Encrypt an outgoing message
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Encrypt(NetOutgoingMessage msg)
|
public override bool Encrypt(NetOutgoingMessage msg)
|
||||||
{
|
{
|
||||||
int numBytes = msg.LengthBytes;
|
int numBytes = msg.LengthBytes;
|
||||||
for (int i = 0; i < numBytes; i++)
|
for (int i = 0; i < numBytes; i++)
|
||||||
@@ -44,7 +52,7 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Decrypt an incoming message
|
/// Decrypt an incoming message
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Decrypt(NetIncomingMessage msg)
|
public override bool Decrypt(NetIncomingMessage msg)
|
||||||
{
|
{
|
||||||
int numBytes = msg.LengthBytes;
|
int numBytes = msg.LengthBytes;
|
||||||
for (int i = 0; i < numBytes; i++)
|
for (int i = 0; i < numBytes; i++)
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 16 byte key
|
/// 16 byte key
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NetXtea(byte[] key, int rounds)
|
public NetXtea(NetPeer peer, byte[] key, int rounds)
|
||||||
|
: base(peer)
|
||||||
{
|
{
|
||||||
if (key.Length < c_keySize)
|
if (key.Length < c_keySize)
|
||||||
throw new NetException("Key too short!");
|
throw new NetException("Key too short!");
|
||||||
@@ -73,19 +74,26 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 16 byte key
|
/// 16 byte key
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NetXtea(byte[] key)
|
public NetXtea(NetPeer peer, byte[] key)
|
||||||
: this(key, 32)
|
: this(peer, key, 32)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// String to hash for key
|
/// String to hash for key
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NetXtea(string key)
|
public NetXtea(NetPeer peer, string key)
|
||||||
: this(SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(key)), 32)
|
: this(peer, NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(key)), 32)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void SetKey(byte[] data, int offset, int length)
|
||||||
|
{
|
||||||
|
var key = NetUtility.ComputeSHAHash(data, offset, length);
|
||||||
|
NetException.Assert(key.Length >= 16);
|
||||||
|
SetKey(key, 0, 16);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Encrypts a block of bytes
|
/// Encrypts a block of bytes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
<RootNamespace>Lidgren.Network</RootNamespace>
|
<RootNamespace>Lidgren.Network</RootNamespace>
|
||||||
<AssemblyName>Lidgren.Network</AssemblyName>
|
<AssemblyName>Lidgren.Network</AssemblyName>
|
||||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
<PublishUrl>publish\</PublishUrl>
|
<PublishUrl>publish\</PublishUrl>
|
||||||
<Install>true</Install>
|
<Install>true</Install>
|
||||||
@@ -39,6 +39,7 @@
|
|||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<DocumentationFile>bin\Debug\Lidgren.Network.XML</DocumentationFile>
|
<DocumentationFile>bin\Debug\Lidgren.Network.XML</DocumentationFile>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
@@ -48,27 +49,34 @@
|
|||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||||
</PropertyGroup>
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
<PropertyGroup>
|
|
||||||
<SignAssembly>true</SignAssembly>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup>
|
|
||||||
<AssemblyOriginatorKeyFile>Lidgren.snk</AssemblyOriginatorKeyFile>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Encryption\INetEncryption.cs" />
|
<Compile Include="Encryption\NetAESEncryption.cs">
|
||||||
<Compile Include="Encryption\NetAESEncryption.cs" />
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Encryption\NetCryptoProviderBase.cs" />
|
||||||
|
<Compile Include="Encryption\NetDESEncryption.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Encryption\NetEncryption.cs" />
|
||||||
<Compile Include="Encryption\NetBlockEncryptionBase.cs" />
|
<Compile Include="Encryption\NetBlockEncryptionBase.cs" />
|
||||||
<Compile Include="Encryption\NetDESEncryption.cs" />
|
<Compile Include="Encryption\NetRC2Encryption.cs">
|
||||||
<Compile Include="Encryption\NetRC2Encryption.cs" />
|
<SubType>Code</SubType>
|
||||||
<Compile Include="Encryption\NetTripleDESEncryption.cs" />
|
</Compile>
|
||||||
<Compile Include="Encryption\NetXorEncryption.cs" />
|
<Compile Include="Encryption\NetTripleDESEncryption.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Encryption\NetXorEncryption.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Encryption\NetXteaEncryption.cs" />
|
<Compile Include="Encryption\NetXteaEncryption.cs" />
|
||||||
<Compile Include="NamespaceDoc.cs" />
|
<Compile Include="NamespaceDoc.cs" />
|
||||||
<Compile Include="NetBigInteger.cs" />
|
<Compile Include="NetBigInteger.cs" />
|
||||||
@@ -109,6 +117,8 @@
|
|||||||
<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="NetRandom.Implementations.cs" />
|
||||||
|
<Compile Include="NetRandomSeed.cs" />
|
||||||
<Compile Include="NetReceiverChannelBase.cs" />
|
<Compile Include="NetReceiverChannelBase.cs" />
|
||||||
<Compile Include="NetReliableOrderedReceiver.cs" />
|
<Compile Include="NetReliableOrderedReceiver.cs" />
|
||||||
<Compile Include="NetReliableSenderChannel.cs" />
|
<Compile Include="NetReliableSenderChannel.cs" />
|
||||||
@@ -126,8 +136,11 @@
|
|||||||
<Compile Include="NetUnreliableUnorderedReceiver.cs" />
|
<Compile Include="NetUnreliableUnorderedReceiver.cs" />
|
||||||
<Compile Include="NetUPnP.cs" />
|
<Compile Include="NetUPnP.cs" />
|
||||||
<Compile Include="NetUtility.cs" />
|
<Compile Include="NetUtility.cs" />
|
||||||
|
<Compile Include="Platform\PlatformAndroid.cs" />
|
||||||
|
<Compile Include="Platform\PlatformConstrained.cs" />
|
||||||
|
<Compile Include="Platform\PlatformWin32.cs" />
|
||||||
|
<Compile Include="Platform\PlatformWinRT.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="SenderChannelBase.cs" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<BootstrapperPackage Include=".NETFramework,Version=v4.0">
|
<BootstrapperPackage Include=".NETFramework,Version=v4.0">
|
||||||
@@ -151,9 +164,6 @@
|
|||||||
<Install>true</Install>
|
<Install>true</Install>
|
||||||
</BootstrapperPackage>
|
</BootstrapperPackage>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<None Include="Lidgren.snk" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
|||||||
Binary file not shown.
@@ -2334,4 +2334,19 @@ namespace Lidgren.Network
|
|||||||
return ((word >> (n % 32)) & 1) > 0;
|
return ((word >> (n % 32)) & 1) > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if WINDOWS_RUNTIME
|
||||||
|
internal sealed class Stack
|
||||||
|
{
|
||||||
|
private System.Collections.Generic.List<object> m_list = new System.Collections.Generic.List<object>();
|
||||||
|
public int Count { get { return m_list.Count; } }
|
||||||
|
public void Push(object item) { m_list.Add(item); }
|
||||||
|
public object Pop()
|
||||||
|
{
|
||||||
|
var item = m_list[m_list.Count - 1];
|
||||||
|
m_list.RemoveAt(m_list.Count - 1);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
@@ -500,8 +500,7 @@ namespace Lidgren.Network
|
|||||||
int num2 = 0;
|
int num2 = 0;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (num2 == 0x23)
|
NetException.Assert(num2 != 0x23, "Bad 7-bit encoded integer");
|
||||||
throw new FormatException("Bad 7-bit encoded integer");
|
|
||||||
|
|
||||||
byte num3 = buffer[offset++];
|
byte num3 = buffer[offset++];
|
||||||
num1 |= (num3 & 0x7f) << (num2 & 0x1f);
|
num1 |= (num3 & 0x7f) << (num2 & 0x1f);
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ namespace Lidgren.Network
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
retval = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
|
retval = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
|
||||||
retval |= NetBitWriter.ReadUInt32(m_data, numberOfBits - 32, m_readPosition) << 32;
|
retval |= (UInt64)NetBitWriter.ReadUInt32(m_data, numberOfBits - 32, m_readPosition + 32) << 32;
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2010 Michael Lidgren
|
/* Copyright (c) 2010 Michael Lidgren
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||||
and associated documentation files (the "Software"), to deal in the Software without
|
and associated documentation files (the "Software"), to deal in the Software without
|
||||||
@@ -37,7 +37,8 @@ namespace Lidgren.Network
|
|||||||
public void ReadAllFields(object target, BindingFlags flags)
|
public void ReadAllFields(object target, BindingFlags flags)
|
||||||
{
|
{
|
||||||
if (target == null)
|
if (target == null)
|
||||||
return;
|
throw new ArgumentNullException("target");
|
||||||
|
|
||||||
Type tp = target.GetType();
|
Type tp = target.GetType();
|
||||||
|
|
||||||
FieldInfo[] fields = tp.GetFields(flags);
|
FieldInfo[] fields = tp.GetFields(flags);
|
||||||
@@ -76,8 +77,6 @@ namespace Lidgren.Network
|
|||||||
if (target == null)
|
if (target == null)
|
||||||
throw new ArgumentNullException("target");
|
throw new ArgumentNullException("target");
|
||||||
|
|
||||||
if (target == null)
|
|
||||||
return;
|
|
||||||
Type tp = target.GetType();
|
Type tp = target.GetType();
|
||||||
|
|
||||||
PropertyInfo[] fields = tp.GetProperties(flags);
|
PropertyInfo[] fields = tp.GetProperties(flags);
|
||||||
@@ -94,10 +93,11 @@ namespace Lidgren.Network
|
|||||||
value = readMethod.Invoke(this, null);
|
value = readMethod.Invoke(this, null);
|
||||||
|
|
||||||
// set the value
|
// set the value
|
||||||
MethodInfo setMethod = fi.GetSetMethod((flags & BindingFlags.NonPublic) == BindingFlags.NonPublic);
|
var setMethod = fi.GetSetMethod();
|
||||||
setMethod.Invoke(target, new object[] { value });
|
if (setMethod != null)
|
||||||
|
setMethod.Invoke(target, new object[] { value });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,10 @@ using System.Text;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
|
#if !__NOIPENDPOINT__
|
||||||
|
using NetEndPoint = System.Net.IPEndPoint;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -311,7 +315,7 @@ namespace Lidgren.Network
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
retval = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
|
retval = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
|
||||||
retval |= NetBitWriter.ReadUInt32(m_data, numberOfBits - 32, m_readPosition) << 32;
|
retval |= (UInt64)NetBitWriter.ReadUInt32(m_data, numberOfBits - 32, m_readPosition + 32) << 32;
|
||||||
}
|
}
|
||||||
m_readPosition += numberOfBits;
|
m_readPosition += numberOfBits;
|
||||||
return retval;
|
return retval;
|
||||||
@@ -406,7 +410,7 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
int num1 = 0;
|
int num1 = 0;
|
||||||
int num2 = 0;
|
int num2 = 0;
|
||||||
while (true)
|
while (m_bitLength - m_readPosition >= 8)
|
||||||
{
|
{
|
||||||
byte num3 = this.ReadByte();
|
byte num3 = this.ReadByte();
|
||||||
num1 |= (num3 & 0x7f) << num2;
|
num1 |= (num3 & 0x7f) << num2;
|
||||||
@@ -414,6 +418,9 @@ namespace Lidgren.Network
|
|||||||
if ((num3 & 0x80) == 0)
|
if ((num3 & 0x80) == 0)
|
||||||
return (uint)num1;
|
return (uint)num1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ouch; failed to find enough bytes; malformed variable length number?
|
||||||
|
return (uint)num1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -424,7 +431,7 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
int num1 = 0;
|
int num1 = 0;
|
||||||
int num2 = 0;
|
int num2 = 0;
|
||||||
while (true)
|
while (m_bitLength - m_readPosition >= 8)
|
||||||
{
|
{
|
||||||
byte num3;
|
byte num3;
|
||||||
if (ReadByte(out num3) == false)
|
if (ReadByte(out num3) == false)
|
||||||
@@ -440,6 +447,8 @@ namespace Lidgren.Network
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
result = (uint)num1;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -468,7 +477,7 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
UInt64 num1 = 0;
|
UInt64 num1 = 0;
|
||||||
int num2 = 0;
|
int num2 = 0;
|
||||||
while (true)
|
while (m_bitLength - m_readPosition >= 8)
|
||||||
{
|
{
|
||||||
//if (num2 == 0x23)
|
//if (num2 == 0x23)
|
||||||
// throw new FormatException("Bad 7-bit encoded integer");
|
// throw new FormatException("Bad 7-bit encoded integer");
|
||||||
@@ -479,6 +488,9 @@ namespace Lidgren.Network
|
|||||||
if ((num3 & 0x80) == 0)
|
if ((num3 & 0x80) == 0)
|
||||||
return num1;
|
return num1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ouch; failed to find enough bytes; malformed variable length number?
|
||||||
|
return num1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -543,10 +555,20 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
int byteLen = (int)ReadVariableUInt32();
|
int byteLen = (int)ReadVariableUInt32();
|
||||||
|
|
||||||
if (byteLen == 0)
|
if (byteLen <= 0)
|
||||||
return String.Empty;
|
return String.Empty;
|
||||||
|
|
||||||
NetException.Assert(m_bitLength - m_readPosition >= (byteLen * 8), c_readOverflowError);
|
if ((ulong)(m_bitLength - m_readPosition) < ((ulong)byteLen * 8))
|
||||||
|
{
|
||||||
|
// not enough data
|
||||||
|
#if DEBUG
|
||||||
|
|
||||||
|
throw new NetException(c_readOverflowError);
|
||||||
|
#else
|
||||||
|
m_readPosition = m_bitLength;
|
||||||
|
return null; // unfortunate; but we need to protect against DDOS
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if ((m_readPosition & 7) == 0)
|
if ((m_readPosition & 7) == 0)
|
||||||
{
|
{
|
||||||
@@ -572,7 +594,7 @@ namespace Lidgren.Network
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (byteLen == 0)
|
if (byteLen <= 0)
|
||||||
{
|
{
|
||||||
result = String.Empty;
|
result = String.Empty;
|
||||||
return true;
|
return true;
|
||||||
@@ -620,14 +642,14 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads a stored IPv4 endpoint description
|
/// Reads a stored IPv4 endpoint description
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IPEndPoint ReadIPEndPoint()
|
public NetEndPoint ReadIPEndPoint()
|
||||||
{
|
{
|
||||||
byte len = ReadByte();
|
byte len = ReadByte();
|
||||||
byte[] addressBytes = ReadBytes(len);
|
byte[] addressBytes = ReadBytes(len);
|
||||||
int port = (int)ReadUInt16();
|
int port = (int)ReadUInt16();
|
||||||
|
|
||||||
IPAddress address = new IPAddress(addressBytes);
|
var address = NetUtility.CreateAddressFromBytes(addressBytes);
|
||||||
return new IPEndPoint(address, port);
|
return new NetEndPoint(address, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -78,13 +78,16 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
foreach (PropertyInfo fi in fields)
|
foreach (PropertyInfo fi in fields)
|
||||||
{
|
{
|
||||||
MethodInfo getMethod = fi.GetGetMethod((flags & BindingFlags.NonPublic) == BindingFlags.NonPublic);
|
MethodInfo getMethod = fi.GetGetMethod();
|
||||||
object value = getMethod.Invoke(ob, null);
|
if (getMethod != null)
|
||||||
|
{
|
||||||
|
object value = getMethod.Invoke(ob, null);
|
||||||
|
|
||||||
// find the appropriate Write method
|
// find the appropriate Write method
|
||||||
MethodInfo writeMethod;
|
MethodInfo writeMethod;
|
||||||
if (s_writeMethods.TryGetValue(fi.PropertyType, out writeMethod))
|
if (s_writeMethods.TryGetValue(fi.PropertyType, out writeMethod))
|
||||||
writeMethod.Invoke(this, new object[] { value });
|
writeMethod.Invoke(this, new object[] { value });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,6 +161,18 @@ namespace Lidgren.Network
|
|||||||
m_bitLength += 16;
|
m_bitLength += 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a 16 bit unsigned integer at a given offset in the buffer
|
||||||
|
/// </summary>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void WriteAt(Int32 offset, UInt16 source)
|
||||||
|
{
|
||||||
|
int newBitLength = Math.Max(m_bitLength, offset + 16);
|
||||||
|
EnsureBufferSize(newBitLength);
|
||||||
|
NetBitWriter.WriteUInt16(source, 16, m_data, offset);
|
||||||
|
m_bitLength = newBitLength;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes an unsigned integer using 1 to 16 bits
|
/// Writes an unsigned integer using 1 to 16 bits
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -183,6 +195,17 @@ namespace Lidgren.Network
|
|||||||
m_bitLength += 16;
|
m_bitLength += 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a 16 bit signed integer at a given offset in the buffer
|
||||||
|
/// </summary>
|
||||||
|
public void WriteAt(Int32 offset, Int16 source)
|
||||||
|
{
|
||||||
|
int newBitLength = Math.Max(m_bitLength, offset + 16);
|
||||||
|
EnsureBufferSize(newBitLength);
|
||||||
|
NetBitWriter.WriteUInt16((ushort)source, 16, m_data, offset);
|
||||||
|
m_bitLength = newBitLength;
|
||||||
|
}
|
||||||
|
|
||||||
#if UNSAFE
|
#if UNSAFE
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes a 32 bit signed integer
|
/// Writes a 32 bit signed integer
|
||||||
@@ -217,6 +240,17 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a 32 bit signed integer at a given offset in the buffer
|
||||||
|
/// </summary>
|
||||||
|
public void WriteAt(Int32 offset, Int32 source)
|
||||||
|
{
|
||||||
|
int newBitLength = Math.Max(m_bitLength, offset + 32);
|
||||||
|
EnsureBufferSize(newBitLength);
|
||||||
|
NetBitWriter.WriteUInt32((UInt32)source, 32, m_data, offset);
|
||||||
|
m_bitLength = newBitLength;
|
||||||
|
}
|
||||||
|
|
||||||
#if UNSAFE
|
#if UNSAFE
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes a 32 bit unsigned integer
|
/// Writes a 32 bit unsigned integer
|
||||||
@@ -253,6 +287,18 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a 32 bit unsigned integer at a given offset in the buffer
|
||||||
|
/// </summary>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void WriteAt(Int32 offset, UInt32 source)
|
||||||
|
{
|
||||||
|
int newBitLength = Math.Max(m_bitLength, offset + 32);
|
||||||
|
EnsureBufferSize(newBitLength);
|
||||||
|
NetBitWriter.WriteUInt32(source, 32, m_data, offset);
|
||||||
|
m_bitLength = newBitLength;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes a 32 bit signed integer
|
/// Writes a 32 bit signed integer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -299,6 +345,18 @@ namespace Lidgren.Network
|
|||||||
m_bitLength += 64;
|
m_bitLength += 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a 64 bit unsigned integer at a given offset in the buffer
|
||||||
|
/// </summary>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void WriteAt(Int32 offset, UInt64 source)
|
||||||
|
{
|
||||||
|
int newBitLength = Math.Max(m_bitLength, offset + 64);
|
||||||
|
EnsureBufferSize(newBitLength);
|
||||||
|
NetBitWriter.WriteUInt64(source, 64, m_data, offset);
|
||||||
|
m_bitLength = newBitLength;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes an unsigned integer using 1 to 64 bits
|
/// Writes an unsigned integer using 1 to 64 bits
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -535,7 +593,6 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(source))
|
if (string.IsNullOrEmpty(source))
|
||||||
{
|
{
|
||||||
EnsureBufferSize(m_bitLength + 8);
|
|
||||||
WriteVariableUInt32(0);
|
WriteVariableUInt32(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||||||
using System;
|
using System;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
|
#if !__NOIPENDPOINT__
|
||||||
|
using NetEndPoint = System.Net.IPEndPoint;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -80,7 +84,7 @@ namespace Lidgren.Network
|
|||||||
/// <param name="remoteEndPoint">The remote endpoint to connect to</param>
|
/// <param name="remoteEndPoint">The remote endpoint to connect to</param>
|
||||||
/// <param name="hailMessage">The hail message to pass</param>
|
/// <param name="hailMessage">The hail message to pass</param>
|
||||||
/// <returns>server connection, or null if already connected</returns>
|
/// <returns>server connection, or null if already connected</returns>
|
||||||
public override NetConnection Connect(IPEndPoint remoteEndPoint, NetOutgoingMessage hailMessage)
|
public override NetConnection Connect(NetEndPoint remoteEndPoint, NetOutgoingMessage hailMessage)
|
||||||
{
|
{
|
||||||
lock (m_connections)
|
lock (m_connections)
|
||||||
{
|
{
|
||||||
@@ -153,6 +157,7 @@ namespace Lidgren.Network
|
|||||||
if (serverConnection == null)
|
if (serverConnection == null)
|
||||||
{
|
{
|
||||||
LogWarning("Cannot send message, no server connection!");
|
LogWarning("Cannot send message, no server connection!");
|
||||||
|
Recycle(msg);
|
||||||
return NetSendResult.FailedNotConnected;
|
return NetSendResult.FailedNotConnected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
#if !__NOIPENDPOINT__
|
||||||
|
using NetEndPoint = System.Net.IPEndPoint;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
@@ -8,10 +13,11 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
internal bool m_connectRequested;
|
internal bool m_connectRequested;
|
||||||
internal bool m_disconnectRequested;
|
internal bool m_disconnectRequested;
|
||||||
internal bool m_connectionInitiator;
|
internal bool m_disconnectReqSendBye;
|
||||||
internal string m_disconnectMessage;
|
internal string m_disconnectMessage;
|
||||||
|
internal bool m_connectionInitiator;
|
||||||
internal NetIncomingMessage m_remoteHailMessage;
|
internal NetIncomingMessage m_remoteHailMessage;
|
||||||
internal float m_lastHandshakeSendTime;
|
internal double m_lastHandshakeSendTime;
|
||||||
internal int m_handshakeAttempts;
|
internal int m_handshakeAttempts;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -20,7 +26,7 @@ namespace Lidgren.Network
|
|||||||
public NetIncomingMessage RemoteHailMessage { get { return m_remoteHailMessage; } }
|
public NetIncomingMessage RemoteHailMessage { get { return m_remoteHailMessage; } }
|
||||||
|
|
||||||
// heartbeat called when connection still is in m_handshakes of NetPeer
|
// heartbeat called when connection still is in m_handshakes of NetPeer
|
||||||
internal void UnconnectedHeartbeat(float now)
|
internal void UnconnectedHeartbeat(double now)
|
||||||
{
|
{
|
||||||
m_peer.VerifyNetworkThread();
|
m_peer.VerifyNetworkThread();
|
||||||
|
|
||||||
@@ -43,7 +49,8 @@ namespace Lidgren.Network
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NetConnectionStatus.Disconnected:
|
case NetConnectionStatus.Disconnected:
|
||||||
throw new NetException("This connection is Disconnected; spent. A new one should have been created");
|
m_peer.ThrowOrLog("This connection is Disconnected; spent. A new one should have been created");
|
||||||
|
break;
|
||||||
|
|
||||||
case NetConnectionStatus.Disconnecting:
|
case NetConnectionStatus.Disconnecting:
|
||||||
// let disconnect finish first
|
// let disconnect finish first
|
||||||
@@ -75,14 +82,12 @@ namespace Lidgren.Network
|
|||||||
case NetConnectionStatus.RespondedConnect:
|
case NetConnectionStatus.RespondedConnect:
|
||||||
SendConnectResponse(now, true);
|
SendConnectResponse(now, true);
|
||||||
break;
|
break;
|
||||||
case NetConnectionStatus.None:
|
|
||||||
case NetConnectionStatus.ReceivedInitiation:
|
|
||||||
m_peer.LogWarning("Time to resend handshake, but status is " + m_status);
|
|
||||||
break;
|
|
||||||
case NetConnectionStatus.RespondedAwaitingApproval:
|
case NetConnectionStatus.RespondedAwaitingApproval:
|
||||||
// awaiting approval
|
// awaiting approval
|
||||||
m_lastHandshakeSendTime = now; // postpone handshake resend
|
m_lastHandshakeSendTime = now; // postpone handshake resend
|
||||||
break;
|
break;
|
||||||
|
case NetConnectionStatus.None:
|
||||||
|
case NetConnectionStatus.ReceivedInitiation:
|
||||||
default:
|
default:
|
||||||
m_peer.LogWarning("Time to resend handshake, but status is " + m_status);
|
m_peer.LogWarning("Time to resend handshake, but status is " + m_status);
|
||||||
break;
|
break;
|
||||||
@@ -94,8 +99,6 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
m_peer.VerifyNetworkThread();
|
m_peer.VerifyNetworkThread();
|
||||||
|
|
||||||
//m_peer.LogDebug("Executing disconnect");
|
|
||||||
|
|
||||||
// clear send queues
|
// clear send queues
|
||||||
for (int i = 0; i < m_sendChannels.Length; i++)
|
for (int i = 0; i < m_sendChannels.Length; i++)
|
||||||
{
|
{
|
||||||
@@ -107,7 +110,15 @@ namespace Lidgren.Network
|
|||||||
if (sendByeMessage)
|
if (sendByeMessage)
|
||||||
SendDisconnect(reason, true);
|
SendDisconnect(reason, true);
|
||||||
|
|
||||||
SetStatus(NetConnectionStatus.Disconnected, reason);
|
if (m_status == NetConnectionStatus.ReceivedInitiation)
|
||||||
|
{
|
||||||
|
// nothing much has happened yet; no need to send disconnected status message
|
||||||
|
m_status = NetConnectionStatus.Disconnected;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetStatus(NetConnectionStatus.Disconnected, reason);
|
||||||
|
}
|
||||||
|
|
||||||
// in case we're still in handshake
|
// in case we're still in handshake
|
||||||
lock (m_peer.m_handshakes)
|
lock (m_peer.m_handshakes)
|
||||||
@@ -118,7 +129,7 @@ namespace Lidgren.Network
|
|||||||
m_handshakeAttempts = 0;
|
m_handshakeAttempts = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void SendConnect(float now)
|
internal void SendConnect(double now)
|
||||||
{
|
{
|
||||||
m_peer.VerifyNetworkThread();
|
m_peer.VerifyNetworkThread();
|
||||||
|
|
||||||
@@ -129,7 +140,7 @@ namespace Lidgren.Network
|
|||||||
om.m_messageType = NetMessageType.Connect;
|
om.m_messageType = NetMessageType.Connect;
|
||||||
om.Write(m_peerConfiguration.AppIdentifier);
|
om.Write(m_peerConfiguration.AppIdentifier);
|
||||||
om.Write(m_peer.m_uniqueIdentifier);
|
om.Write(m_peer.m_uniqueIdentifier);
|
||||||
om.Write(now);
|
om.Write((float)now);
|
||||||
|
|
||||||
WriteLocalHail(om);
|
WriteLocalHail(om);
|
||||||
|
|
||||||
@@ -144,7 +155,7 @@ namespace Lidgren.Network
|
|||||||
SetStatus(NetConnectionStatus.InitiatedConnect, "Locally requested connect");
|
SetStatus(NetConnectionStatus.InitiatedConnect, "Locally requested connect");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void SendConnectResponse(float now, bool onLibraryThread)
|
internal void SendConnectResponse(double now, bool onLibraryThread)
|
||||||
{
|
{
|
||||||
if (onLibraryThread)
|
if (onLibraryThread)
|
||||||
m_peer.VerifyNetworkThread();
|
m_peer.VerifyNetworkThread();
|
||||||
@@ -153,14 +164,14 @@ namespace Lidgren.Network
|
|||||||
om.m_messageType = NetMessageType.ConnectResponse;
|
om.m_messageType = NetMessageType.ConnectResponse;
|
||||||
om.Write(m_peerConfiguration.AppIdentifier);
|
om.Write(m_peerConfiguration.AppIdentifier);
|
||||||
om.Write(m_peer.m_uniqueIdentifier);
|
om.Write(m_peer.m_uniqueIdentifier);
|
||||||
om.Write(now);
|
om.Write((float)now);
|
||||||
|
Interlocked.Increment(ref om.m_recyclingCount);
|
||||||
WriteLocalHail(om);
|
WriteLocalHail(om);
|
||||||
|
|
||||||
if (onLibraryThread)
|
if (onLibraryThread)
|
||||||
m_peer.SendLibrary(om, m_remoteEndPoint);
|
m_peer.SendLibrary(om, m_remoteEndPoint);
|
||||||
else
|
else
|
||||||
m_peer.m_unsentUnconnectedMessages.Enqueue(new NetTuple<System.Net.IPEndPoint, NetOutgoingMessage>(m_remoteEndPoint, om));
|
m_peer.m_unsentUnconnectedMessages.Enqueue(new NetTuple<NetEndPoint, NetOutgoingMessage>(m_remoteEndPoint, om));
|
||||||
|
|
||||||
m_lastHandshakeSendTime = now;
|
m_lastHandshakeSendTime = now;
|
||||||
m_handshakeAttempts++;
|
m_handshakeAttempts++;
|
||||||
@@ -178,10 +189,11 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
NetOutgoingMessage om = m_peer.CreateMessage(reason);
|
NetOutgoingMessage om = m_peer.CreateMessage(reason);
|
||||||
om.m_messageType = NetMessageType.Disconnect;
|
om.m_messageType = NetMessageType.Disconnect;
|
||||||
|
Interlocked.Increment(ref om.m_recyclingCount);
|
||||||
if (onLibraryThread)
|
if (onLibraryThread)
|
||||||
m_peer.SendLibrary(om, m_remoteEndPoint);
|
m_peer.SendLibrary(om, m_remoteEndPoint);
|
||||||
else
|
else
|
||||||
m_peer.m_unsentUnconnectedMessages.Enqueue(new NetTuple<System.Net.IPEndPoint, NetOutgoingMessage>(m_remoteEndPoint, om));
|
m_peer.m_unsentUnconnectedMessages.Enqueue(new NetTuple<NetEndPoint, NetOutgoingMessage>(m_remoteEndPoint, om));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteLocalHail(NetOutgoingMessage om)
|
private void WriteLocalHail(NetOutgoingMessage om)
|
||||||
@@ -192,7 +204,7 @@ namespace Lidgren.Network
|
|||||||
if (hi != null && hi.Length >= m_localHailMessage.LengthBytes)
|
if (hi != null && hi.Length >= m_localHailMessage.LengthBytes)
|
||||||
{
|
{
|
||||||
if (om.LengthBytes + m_localHailMessage.LengthBytes > m_peerConfiguration.m_maximumTransmissionUnit - 10)
|
if (om.LengthBytes + m_localHailMessage.LengthBytes > m_peerConfiguration.m_maximumTransmissionUnit - 10)
|
||||||
throw new NetException("Hail message too large; can maximally be " + (m_peerConfiguration.m_maximumTransmissionUnit - 10 - om.LengthBytes));
|
m_peer.ThrowOrLog("Hail message too large; can maximally be " + (m_peerConfiguration.m_maximumTransmissionUnit - 10 - om.LengthBytes));
|
||||||
om.Write(m_localHailMessage.Data, 0, m_localHailMessage.LengthBytes);
|
om.Write(m_localHailMessage.Data, 0, m_localHailMessage.LengthBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,7 +237,7 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
m_localHailMessage = null;
|
m_localHailMessage = null;
|
||||||
m_handshakeAttempts = 0;
|
m_handshakeAttempts = 0;
|
||||||
SendConnectResponse((float)NetTime.Now, false);
|
SendConnectResponse(NetTime.Now, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -242,7 +254,7 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
m_localHailMessage = localHail;
|
m_localHailMessage = localHail;
|
||||||
m_handshakeAttempts = 0;
|
m_handshakeAttempts = 0;
|
||||||
SendConnectResponse((float)NetTime.Now, false);
|
SendConnectResponse(NetTime.Now, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -263,7 +275,8 @@ namespace Lidgren.Network
|
|||||||
SendDisconnect(reason, false);
|
SendDisconnect(reason, false);
|
||||||
|
|
||||||
// remove from handshakes
|
// remove from handshakes
|
||||||
m_peer.m_handshakes.Remove(m_remoteEndPoint); // TODO: make this more thread safe? we're on user thread
|
lock (m_peer.m_handshakes)
|
||||||
|
m_peer.m_handshakes.Remove(m_remoteEndPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ReceivedHandshake(double now, NetMessageType tp, int ptr, int payloadLength)
|
internal void ReceivedHandshake(double now, NetMessageType tp, int ptr, int payloadLength)
|
||||||
@@ -322,43 +335,9 @@ namespace Lidgren.Network
|
|||||||
m_peer.LogDebug("Unhandled Connect: " + tp + ", status is " + m_status + " length: " + payloadLength);
|
m_peer.LogDebug("Unhandled Connect: " + tp + ", status is " + m_status + " length: " + payloadLength);
|
||||||
break;
|
break;
|
||||||
case NetMessageType.ConnectResponse:
|
case NetMessageType.ConnectResponse:
|
||||||
switch (m_status)
|
HandleConnectResponse(now, tp, ptr, payloadLength);
|
||||||
{
|
|
||||||
case NetConnectionStatus.InitiatedConnect:
|
|
||||||
// awesome
|
|
||||||
bool ok = ValidateHandshakeData(ptr, payloadLength, out hail);
|
|
||||||
if (ok)
|
|
||||||
{
|
|
||||||
if (hail != null)
|
|
||||||
{
|
|
||||||
m_remoteHailMessage = m_peer.CreateIncomingMessage(NetIncomingMessageType.Data, hail);
|
|
||||||
m_remoteHailMessage.LengthBits = (hail.Length * 8);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_remoteHailMessage = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_peer.AcceptConnection(this);
|
|
||||||
SendConnectionEstablished();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NetConnectionStatus.RespondedConnect:
|
|
||||||
// hello, wtf?
|
|
||||||
break;
|
|
||||||
case NetConnectionStatus.Disconnecting:
|
|
||||||
case NetConnectionStatus.Disconnected:
|
|
||||||
case NetConnectionStatus.ReceivedInitiation:
|
|
||||||
case NetConnectionStatus.None:
|
|
||||||
// wtf? anyway, bye!
|
|
||||||
break;
|
|
||||||
case NetConnectionStatus.Connected:
|
|
||||||
// my ConnectionEstablished must have been lost, send another one
|
|
||||||
SendConnectionEstablished();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NetMessageType.ConnectionEstablished:
|
case NetMessageType.ConnectionEstablished:
|
||||||
switch (m_status)
|
switch (m_status)
|
||||||
{
|
{
|
||||||
@@ -421,6 +400,47 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void HandleConnectResponse(double now, NetMessageType tp, int ptr, int payloadLength)
|
||||||
|
{
|
||||||
|
byte[] hail;
|
||||||
|
switch (m_status)
|
||||||
|
{
|
||||||
|
case NetConnectionStatus.InitiatedConnect:
|
||||||
|
// awesome
|
||||||
|
bool ok = ValidateHandshakeData(ptr, payloadLength, out hail);
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
if (hail != null)
|
||||||
|
{
|
||||||
|
m_remoteHailMessage = m_peer.CreateIncomingMessage(NetIncomingMessageType.Data, hail);
|
||||||
|
m_remoteHailMessage.LengthBits = (hail.Length * 8);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_remoteHailMessage = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_peer.AcceptConnection(this);
|
||||||
|
SendConnectionEstablished();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NetConnectionStatus.RespondedConnect:
|
||||||
|
// hello, wtf?
|
||||||
|
break;
|
||||||
|
case NetConnectionStatus.Disconnecting:
|
||||||
|
case NetConnectionStatus.Disconnected:
|
||||||
|
case NetConnectionStatus.ReceivedInitiation:
|
||||||
|
case NetConnectionStatus.None:
|
||||||
|
// wtf? anyway, bye!
|
||||||
|
break;
|
||||||
|
case NetConnectionStatus.Connected:
|
||||||
|
// my ConnectionEstablished must have been lost, send another one
|
||||||
|
SendConnectionEstablished();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private bool ValidateHandshakeData(int ptr, int payloadLength, out byte[] hail)
|
private bool ValidateHandshakeData(int ptr, int payloadLength, out byte[] hail)
|
||||||
{
|
{
|
||||||
hail = null;
|
hail = null;
|
||||||
@@ -439,7 +459,6 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
if (remoteAppIdentifier != m_peer.m_configuration.AppIdentifier)
|
if (remoteAppIdentifier != m_peer.m_configuration.AppIdentifier)
|
||||||
{
|
{
|
||||||
// wrong app identifier
|
|
||||||
ExecuteDisconnect("Wrong application identifier!", true);
|
ExecuteDisconnect("Wrong application identifier!", true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -474,6 +493,7 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
m_handshakeAttempts = 0;
|
m_handshakeAttempts = 0;
|
||||||
m_disconnectRequested = true;
|
m_disconnectRequested = true;
|
||||||
|
m_disconnectReqSendBye = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
public partial class NetConnection
|
public partial class NetConnection
|
||||||
{
|
{
|
||||||
private float m_sentPingTime;
|
private double m_sentPingTime;
|
||||||
private int m_sentPingNumber;
|
private int m_sentPingNumber;
|
||||||
private float m_averageRoundtripTime;
|
private double m_averageRoundtripTime;
|
||||||
private float m_timeoutDeadline = float.MaxValue;
|
private double m_timeoutDeadline = double.MaxValue;
|
||||||
|
|
||||||
// local time value + m_remoteTimeOffset = remote time value
|
// local time value + m_remoteTimeOffset = remote time value
|
||||||
internal double m_remoteTimeOffset;
|
internal double m_remoteTimeOffset;
|
||||||
@@ -15,7 +15,7 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the current average roundtrip time in seconds
|
/// Gets the current average roundtrip time in seconds
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float AverageRoundtripTime { get { return m_averageRoundtripTime; } }
|
public float AverageRoundtripTime { get { return (float)m_averageRoundtripTime; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Time offset between this peer and the remote peer
|
/// Time offset between this peer and the remote peer
|
||||||
@@ -46,13 +46,13 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
internal void InitializePing()
|
internal void InitializePing()
|
||||||
{
|
{
|
||||||
float now = (float)NetTime.Now;
|
double now = NetTime.Now;
|
||||||
|
|
||||||
// randomize ping sent time (0.25 - 1.0 x ping interval)
|
// randomize ping sent time (0.25 - 1.0 x ping interval)
|
||||||
m_sentPingTime = now;
|
m_sentPingTime = now;
|
||||||
m_sentPingTime -= (m_peerConfiguration.PingInterval * 0.25f); // delay ping for a little while
|
m_sentPingTime -= (m_peerConfiguration.PingInterval * 0.25f); // delay ping for a little while
|
||||||
m_sentPingTime -= (NetRandom.Instance.NextSingle() * (m_peerConfiguration.PingInterval * 0.75f));
|
m_sentPingTime -= (MWCRandom.Instance.NextSingle() * (m_peerConfiguration.PingInterval * 0.75f));
|
||||||
m_timeoutDeadline = now + (m_peerConfiguration.m_connectionTimeout * 2.0f); // initially allow a little more time
|
m_timeoutDeadline = now + (m_peerConfiguration.m_connectionTimeout * 2.0); // initially allow a little more time
|
||||||
|
|
||||||
// make it better, quick :-)
|
// make it better, quick :-)
|
||||||
SendPing();
|
SendPing();
|
||||||
@@ -64,7 +64,7 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
m_sentPingNumber++;
|
m_sentPingNumber++;
|
||||||
|
|
||||||
m_sentPingTime = (float)NetTime.Now;
|
m_sentPingTime = NetTime.Now;
|
||||||
NetOutgoingMessage om = m_peer.CreateMessage(1);
|
NetOutgoingMessage om = m_peer.CreateMessage(1);
|
||||||
om.Write((byte)m_sentPingNumber); // truncating to 0-255
|
om.Write((byte)m_sentPingNumber); // truncating to 0-255
|
||||||
om.m_messageType = NetMessageType.Ping;
|
om.m_messageType = NetMessageType.Ping;
|
||||||
@@ -74,6 +74,7 @@ namespace Lidgren.Network
|
|||||||
m_peer.SendPacket(len, m_remoteEndPoint, 1, out connectionReset);
|
m_peer.SendPacket(len, m_remoteEndPoint, 1, out connectionReset);
|
||||||
|
|
||||||
m_statistics.PacketSent(len, 1);
|
m_statistics.PacketSent(len, 1);
|
||||||
|
m_peer.Recycle(om);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void SendPong(int pingNumber)
|
internal void SendPong(int pingNumber)
|
||||||
@@ -91,9 +92,10 @@ namespace Lidgren.Network
|
|||||||
m_peer.SendPacket(len, m_remoteEndPoint, 1, out connectionReset);
|
m_peer.SendPacket(len, m_remoteEndPoint, 1, out connectionReset);
|
||||||
|
|
||||||
m_statistics.PacketSent(len, 1);
|
m_statistics.PacketSent(len, 1);
|
||||||
|
m_peer.Recycle(om);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ReceivedPong(float now, int pongNumber, float remoteSendTime)
|
internal void ReceivedPong(double now, int pongNumber, float remoteSendTime)
|
||||||
{
|
{
|
||||||
if ((byte)pongNumber != (byte)m_sentPingNumber)
|
if ((byte)pongNumber != (byte)m_sentPingNumber)
|
||||||
{
|
{
|
||||||
@@ -103,7 +105,7 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
m_timeoutDeadline = now + m_peerConfiguration.m_connectionTimeout;
|
m_timeoutDeadline = now + m_peerConfiguration.m_connectionTimeout;
|
||||||
|
|
||||||
float rtt = now - m_sentPingTime;
|
double rtt = now - m_sentPingTime;
|
||||||
NetException.Assert(rtt >= 0);
|
NetException.Assert(rtt >= 0);
|
||||||
|
|
||||||
double diff = (remoteSendTime + (rtt / 2.0)) - now;
|
double diff = (remoteSendTime + (rtt / 2.0)) - now;
|
||||||
@@ -116,14 +118,14 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_averageRoundtripTime = (m_averageRoundtripTime * 0.7f) + (float)(rtt * 0.3f);
|
m_averageRoundtripTime = (m_averageRoundtripTime * 0.7) + (rtt * 0.3);
|
||||||
|
|
||||||
m_remoteTimeOffset = ((m_remoteTimeOffset * (double)(m_sentPingNumber - 1)) + diff) / (double)m_sentPingNumber;
|
m_remoteTimeOffset = ((m_remoteTimeOffset * (double)(m_sentPingNumber - 1)) + diff) / (double)m_sentPingNumber;
|
||||||
m_peer.LogVerbose("Updated average roundtrip time to " + NetTime.ToReadable(m_averageRoundtripTime) + ", remote time to " + (now + m_remoteTimeOffset) + " (ie. diff " + m_remoteTimeOffset + ")");
|
m_peer.LogVerbose("Updated average roundtrip time to " + NetTime.ToReadable(m_averageRoundtripTime) + ", remote time to " + (now + m_remoteTimeOffset) + " (ie. diff " + m_remoteTimeOffset + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
// update resend delay for all channels
|
// update resend delay for all channels
|
||||||
float resendDelay = GetResendDelay();
|
double resendDelay = GetResendDelay();
|
||||||
foreach (var chan in m_sendChannels)
|
foreach (var chan in m_sendChannels)
|
||||||
{
|
{
|
||||||
var rchan = chan as NetReliableSenderChannel;
|
var rchan = chan as NetReliableSenderChannel;
|
||||||
@@ -139,7 +141,7 @@ namespace Lidgren.Network
|
|||||||
NetIncomingMessage update = m_peer.CreateIncomingMessage(NetIncomingMessageType.ConnectionLatencyUpdated, 4);
|
NetIncomingMessage update = m_peer.CreateIncomingMessage(NetIncomingMessageType.ConnectionLatencyUpdated, 4);
|
||||||
update.m_senderConnection = this;
|
update.m_senderConnection = this;
|
||||||
update.m_senderEndPoint = this.m_remoteEndPoint;
|
update.m_senderEndPoint = this.m_remoteEndPoint;
|
||||||
update.Write(rtt);
|
update.Write((float)rtt);
|
||||||
m_peer.ReleaseMessage(update);
|
m_peer.ReleaseMessage(update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,11 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
internal int m_currentMTU;
|
internal int m_currentMTU;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current MTU in bytes. If PeerConfiguration.AutoExpandMTU is false, this will be PeerConfiguration.MaximumTransmissionUnit.
|
||||||
|
/// </summary>
|
||||||
|
public int CurrentMTU { get { return m_currentMTU; } }
|
||||||
|
|
||||||
internal void InitExpandMTU(double now)
|
internal void InitExpandMTU(double now)
|
||||||
{
|
{
|
||||||
m_lastSentMTUAttemptTime = now + m_peerConfiguration.m_expandMTUFrequency + 1.5f + m_averageRoundtripTime; // wait a tiny bit before starting to expand mtu
|
m_lastSentMTUAttemptTime = now + m_peerConfiguration.m_expandMTUFrequency + 1.5f + m_averageRoundtripTime; // wait a tiny bit before starting to expand mtu
|
||||||
@@ -128,6 +133,7 @@ namespace Lidgren.Network
|
|||||||
m_lastSentMTUAttemptTime = now;
|
m_lastSentMTUAttemptTime = now;
|
||||||
|
|
||||||
m_statistics.PacketSent(len, 1);
|
m_statistics.PacketSent(len, 1);
|
||||||
|
m_peer.Recycle(om);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FinalizeMTU(int size)
|
private void FinalizeMTU(int size)
|
||||||
@@ -149,8 +155,9 @@ namespace Lidgren.Network
|
|||||||
int len = om.Encode(m_peer.m_sendBuffer, 0, 0);
|
int len = om.Encode(m_peer.m_sendBuffer, 0, 0);
|
||||||
bool connectionReset;
|
bool connectionReset;
|
||||||
m_peer.SendPacket(len, m_remoteEndPoint, 1, out connectionReset);
|
m_peer.SendPacket(len, m_remoteEndPoint, 1, out connectionReset);
|
||||||
|
m_peer.Recycle(om);
|
||||||
|
|
||||||
// m_peer.LogDebug("Received MTU expand request for " + size + " bytes");
|
//m_peer.LogDebug("Received MTU expand request for " + size + " bytes");
|
||||||
|
|
||||||
m_statistics.PacketSent(len, 1);
|
m_statistics.PacketSent(len, 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,16 @@ using System.Net;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
#if !__NOIPENDPOINT__
|
||||||
|
using NetEndPoint = System.Net.IPEndPoint;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a connection to a remote peer
|
/// Represents a connection to a remote peer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DebuggerDisplay("RemoteUniqueIdentifier={RemoteUniqueIdentifier} RemoteEndPoint={remoteEndPoint}")]
|
[DebuggerDisplay("RemoteUniqueIdentifier={RemoteUniqueIdentifier} RemoteEndPoint={m_remoteEndPoint}")]
|
||||||
public partial class NetConnection
|
public partial class NetConnection
|
||||||
{
|
{
|
||||||
private const int m_infrequentEventsSkipFrames = 8; // number of heartbeats to skip checking for infrequent events (ping, timeout etc)
|
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 NetPeer m_peer;
|
||||||
internal NetPeerConfiguration m_peerConfiguration;
|
internal NetPeerConfiguration m_peerConfiguration;
|
||||||
internal NetConnectionStatus m_status;
|
internal NetConnectionStatus m_status; // actual status
|
||||||
internal NetConnectionStatus m_visibleStatus;
|
internal NetConnectionStatus m_outputtedStatus; // status that has been sent as StatusChanged message
|
||||||
internal IPEndPoint m_remoteEndPoint;
|
internal NetConnectionStatus m_visibleStatus; // status visible by querying the Status property
|
||||||
|
internal NetEndPoint m_remoteEndPoint;
|
||||||
internal NetSenderChannelBase[] m_sendChannels;
|
internal NetSenderChannelBase[] m_sendChannels;
|
||||||
internal NetReceiverChannelBase[] m_receiveChannels;
|
internal NetReceiverChannelBase[] m_receiveChannels;
|
||||||
internal NetOutgoingMessage m_localHailMessage;
|
internal NetOutgoingMessage m_localHailMessage;
|
||||||
@@ -57,7 +62,7 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the remote endpoint for the connection
|
/// Gets the remote endpoint for the connection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IPEndPoint RemoteEndPoint { get { return m_remoteEndPoint; } }
|
public NetEndPoint RemoteEndPoint { get { return m_remoteEndPoint; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the unique identifier of the remote NetPeer for this connection
|
/// 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; } }
|
public NetOutgoingMessage LocalHailMessage { get { return m_localHailMessage; } }
|
||||||
|
|
||||||
// gets the time before automatically resending an unacked message
|
// 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)
|
if (avgRtt <= 0)
|
||||||
avgRtt = 0.1f; // "default" resend is based on 100 ms roundtrip time
|
avgRtt = 0.1; // "default" resend is based on 100 ms roundtrip time
|
||||||
return 0.02f + (avgRtt * 2.0f); // 20 ms + double rtt
|
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_peer = peer;
|
||||||
m_peerConfiguration = m_peer.Configuration;
|
m_peerConfiguration = m_peer.Configuration;
|
||||||
m_status = NetConnectionStatus.None;
|
m_status = NetConnectionStatus.None;
|
||||||
|
m_outputtedStatus = NetConnectionStatus.None;
|
||||||
m_visibleStatus = NetConnectionStatus.None;
|
m_visibleStatus = NetConnectionStatus.None;
|
||||||
m_remoteEndPoint = remoteEndPoint;
|
m_remoteEndPoint = remoteEndPoint;
|
||||||
m_sendChannels = new NetSenderChannelBase[NetConstants.NumTotalChannels];
|
m_sendChannels = new NetSenderChannelBase[NetConstants.NumTotalChannels];
|
||||||
@@ -97,45 +103,52 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Change the internal endpoint to this new one. Used when, during handshake, a switch in port is detected (due to NAT)
|
/// Change the internal endpoint to this new one. Used when, during handshake, a switch in port is detected (due to NAT)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal void MutateEndPoint(IPEndPoint endPoint)
|
internal void MutateEndPoint(NetEndPoint endPoint)
|
||||||
{
|
{
|
||||||
m_remoteEndPoint = endPoint;
|
m_remoteEndPoint = endPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void ResetTimeout(double now)
|
||||||
|
{
|
||||||
|
m_timeoutDeadline = now + m_peerConfiguration.m_connectionTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
internal void SetStatus(NetConnectionStatus status, string reason)
|
internal void SetStatus(NetConnectionStatus status, string reason)
|
||||||
{
|
{
|
||||||
// user or library thread
|
// user or library thread
|
||||||
|
|
||||||
if (status == m_status)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_status = status;
|
m_status = status;
|
||||||
if (reason == null)
|
if (reason == null)
|
||||||
reason = string.Empty;
|
reason = string.Empty;
|
||||||
|
|
||||||
if (m_status == NetConnectionStatus.Connected)
|
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);
|
m_peer.LogVerbose("Timeout deadline initialized to " + m_timeoutDeadline);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_peerConfiguration.IsMessageTypeEnabled(NetIncomingMessageType.StatusChanged))
|
if (m_peerConfiguration.IsMessageTypeEnabled(NetIncomingMessageType.StatusChanged))
|
||||||
{
|
{
|
||||||
NetIncomingMessage info = m_peer.CreateIncomingMessage(NetIncomingMessageType.StatusChanged, 4 + reason.Length + (reason.Length > 126 ? 2 : 1));
|
if (m_outputtedStatus != status)
|
||||||
info.m_senderConnection = this;
|
{
|
||||||
info.m_senderEndPoint = m_remoteEndPoint;
|
NetIncomingMessage info = m_peer.CreateIncomingMessage(NetIncomingMessageType.StatusChanged, 4 + reason.Length + (reason.Length > 126 ? 2 : 1));
|
||||||
info.Write((byte)m_status);
|
info.m_senderConnection = this;
|
||||||
info.Write(reason);
|
info.m_senderEndPoint = m_remoteEndPoint;
|
||||||
m_peer.ReleaseMessage(info);
|
info.Write((byte)m_status);
|
||||||
|
info.Write(reason);
|
||||||
|
m_peer.ReleaseMessage(info);
|
||||||
|
m_outputtedStatus = status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// app dont want those messages, update visible status immediately
|
// app dont want those messages, update visible status immediately
|
||||||
|
m_outputtedStatus = m_status;
|
||||||
m_visibleStatus = m_status;
|
m_visibleStatus = m_status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Heartbeat(float now, uint frameCounter)
|
internal void Heartbeat(double now, uint frameCounter)
|
||||||
{
|
{
|
||||||
m_peer.VerifyNetworkThread();
|
m_peer.VerifyNetworkThread();
|
||||||
|
|
||||||
@@ -150,6 +163,7 @@ namespace Lidgren.Network
|
|||||||
//
|
//
|
||||||
m_peer.LogVerbose("Connection timed out at " + now + " deadline was " + m_timeoutDeadline);
|
m_peer.LogVerbose("Connection timed out at " + now + " deadline was " + m_timeoutDeadline);
|
||||||
ExecuteDisconnect("Connection timed out", true);
|
ExecuteDisconnect("Connection timed out", true);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send ping?
|
// send ping?
|
||||||
@@ -164,7 +178,7 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
if (m_disconnectRequested)
|
if (m_disconnectRequested)
|
||||||
{
|
{
|
||||||
ExecuteDisconnect(m_disconnectMessage, true);
|
ExecuteDisconnect(m_disconnectMessage, m_disconnectReqSendBye);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,8 +247,11 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
//m_peer.LogVerbose("Received ack for " + acktp + "#" + seqNr);
|
//m_peer.LogVerbose("Received ack for " + acktp + "#" + seqNr);
|
||||||
NetSenderChannelBase chan = m_sendChannels[(int)incAck.Item1 - 1];
|
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)
|
if (chan == null)
|
||||||
chan = CreateSenderChannel(incAck.Item1);
|
continue;
|
||||||
|
|
||||||
chan.ReceiveAcknowledge(now, incAck.Item2);
|
chan.ReceiveAcknowledge(now, incAck.Item2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -249,7 +266,11 @@ namespace Lidgren.Network
|
|||||||
var channel = m_sendChannels[i];
|
var channel = m_sendChannels[i];
|
||||||
NetException.Assert(m_sendBufferWritePtr < 1 || m_sendBufferNumMessages > 0);
|
NetException.Assert(m_sendBufferWritePtr < 1 || m_sendBufferNumMessages > 0);
|
||||||
if (channel != null)
|
if (channel != null)
|
||||||
|
{
|
||||||
channel.SendQueuedMessages(now);
|
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);
|
NetException.Assert(m_sendBufferWritePtr < 1 || m_sendBufferNumMessages > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -275,24 +296,41 @@ namespace Lidgren.Network
|
|||||||
m_peer.VerifyNetworkThread();
|
m_peer.VerifyNetworkThread();
|
||||||
|
|
||||||
int sz = om.GetEncodedSize();
|
int sz = om.GetEncodedSize();
|
||||||
if (sz > m_currentMTU)
|
//if (sz > m_currentMTU)
|
||||||
m_peer.LogWarning("Message larger than MTU! Fragmentation must have failed!");
|
// 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)
|
if (m_sendBufferWritePtr + sz > m_currentMTU)
|
||||||
{
|
{
|
||||||
bool connReset; // TODO: handle connection reset
|
if (m_sendBufferWritePtr > 0 && m_sendBufferNumMessages > 0)
|
||||||
NetException.Assert(m_sendBufferWritePtr > 0 && m_sendBufferNumMessages > 0); // or else the message should have been fragmented earlier
|
{
|
||||||
|
// 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_peer.SendPacket(m_sendBufferWritePtr, m_remoteEndPoint, m_sendBufferNumMessages, out connReset);
|
||||||
m_statistics.PacketSent(m_sendBufferWritePtr, m_sendBufferNumMessages);
|
m_statistics.PacketSent(m_sendBufferWritePtr, m_sendBufferNumMessages);
|
||||||
m_sendBufferWritePtr = 0;
|
m_sendBufferWritePtr = 0;
|
||||||
m_sendBufferNumMessages = 0;
|
m_sendBufferNumMessages = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_sendBufferWritePtr = om.Encode(m_peer.m_sendBuffer, m_sendBufferWritePtr, seqNr);
|
if (m_sendBufferWritePtr > 0)
|
||||||
m_sendBufferNumMessages++;
|
m_peer.m_needFlushSendQueue = true; // flush in heartbeat
|
||||||
|
|
||||||
NetException.Assert(m_sendBufferWritePtr > 0, "Encoded zero size message?");
|
Interlocked.Decrement(ref om.m_recyclingCount);
|
||||||
NetException.Assert(m_sendBufferNumMessages > 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -321,12 +359,12 @@ namespace Lidgren.Network
|
|||||||
if (chan == null)
|
if (chan == null)
|
||||||
chan = CreateSenderChannel(tp);
|
chan = CreateSenderChannel(tp);
|
||||||
|
|
||||||
if (msg.GetEncodedSize() > m_currentMTU)
|
if ((method != NetDeliveryMethod.Unreliable && method != NetDeliveryMethod.UnreliableSequenced) && msg.GetEncodedSize() > m_currentMTU)
|
||||||
throw new NetException("Message too large! Fragmentation failure?");
|
m_peer.ThrowOrLog("Reliable message too large! Fragmentation failure?");
|
||||||
|
|
||||||
var retval = chan.Enqueue(msg);
|
var retval = chan.Enqueue(msg);
|
||||||
if (retval == NetSendResult.Sent && m_peerConfiguration.m_autoFlushSendQueue == false)
|
//if (retval == NetSendResult.Sent && m_peerConfiguration.m_autoFlushSendQueue == false)
|
||||||
retval = NetSendResult.Queued; // queued since we're not autoflushing
|
// retval = NetSendResult.Queued; // queued since we're not autoflushing
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,12 +385,11 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
switch (method)
|
switch (method)
|
||||||
{
|
{
|
||||||
case NetDeliveryMethod.Unreliable:
|
case NetDeliveryMethod.Unreliable:
|
||||||
case NetDeliveryMethod.UnreliableSequenced:
|
case NetDeliveryMethod.UnreliableSequenced:
|
||||||
chan = new NetUnreliableSenderChannel(this, NetUtility.GetWindowSize(method));
|
chan = new NetUnreliableSenderChannel(this, NetUtility.GetWindowSize(method), method);
|
||||||
break;
|
break;
|
||||||
case NetDeliveryMethod.ReliableOrdered:
|
case NetDeliveryMethod.ReliableOrdered:
|
||||||
chan = new NetReliableSenderChannel(this, NetUtility.GetWindowSize(method));
|
chan = new NetReliableSenderChannel(this, NetUtility.GetWindowSize(method));
|
||||||
@@ -375,13 +412,34 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
m_peer.VerifyNetworkThread();
|
m_peer.VerifyNetworkThread();
|
||||||
|
|
||||||
float now = (float)NetTime.Now;
|
double now = NetTime.Now;
|
||||||
|
|
||||||
switch (tp)
|
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:
|
case NetMessageType.Disconnect:
|
||||||
NetIncomingMessage msg = m_peer.SetupReadHelperMessage(ptr, payloadLength);
|
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;
|
break;
|
||||||
case NetMessageType.Acknowledge:
|
case NetMessageType.Acknowledge:
|
||||||
for (int i = 0; i < payloadLength; i+=3)
|
for (int i = 0; i < payloadLength; i+=3)
|
||||||
@@ -408,6 +466,11 @@ namespace Lidgren.Network
|
|||||||
SendMTUSuccess(payloadLength);
|
SendMTUSuccess(payloadLength);
|
||||||
break;
|
break;
|
||||||
case NetMessageType.ExpandMTUSuccess:
|
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);
|
NetIncomingMessage emsg = m_peer.SetupReadHelperMessage(ptr, payloadLength);
|
||||||
int size = emsg.ReadInt32();
|
int size = emsg.ReadInt32();
|
||||||
HandleExpandMTUSuccess(now, size);
|
HandleExpandMTUSuccess(now, size);
|
||||||
@@ -492,10 +555,19 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
|
|
||||||
windowSize = chan.WindowSize;
|
windowSize = chan.WindowSize;
|
||||||
freeWindowSlots = chan.GetAllowedSends() - chan.m_queuedSends.Count;
|
freeWindowSlots = chan.GetFreeWindowSlots();
|
||||||
return;
|
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)
|
internal void Shutdown(string reason)
|
||||||
{
|
{
|
||||||
ExecuteDisconnect(reason, true);
|
ExecuteDisconnect(reason, true);
|
||||||
|
|||||||
@@ -40,17 +40,19 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
private readonly NetConnection m_connection;
|
private readonly NetConnection m_connection;
|
||||||
|
|
||||||
internal int m_sentPackets;
|
internal long m_sentPackets;
|
||||||
internal int m_receivedPackets;
|
internal long m_receivedPackets;
|
||||||
|
|
||||||
internal int m_sentMessages;
|
internal long m_sentMessages;
|
||||||
internal int m_receivedMessages;
|
internal long m_receivedMessages;
|
||||||
|
internal long m_droppedMessages;
|
||||||
|
internal long m_receivedFragments;
|
||||||
|
|
||||||
internal int m_sentBytes;
|
internal long m_sentBytes;
|
||||||
internal int m_receivedBytes;
|
internal long m_receivedBytes;
|
||||||
|
|
||||||
internal int m_resentMessagesDueToDelay;
|
internal long m_resentMessagesDueToDelay;
|
||||||
internal int m_resentMessagesDueToHole;
|
internal long m_resentMessagesDueToHole;
|
||||||
|
|
||||||
internal NetConnectionStatistics(NetConnection conn)
|
internal NetConnectionStatistics(NetConnection conn)
|
||||||
{
|
{
|
||||||
@@ -62,38 +64,60 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
m_sentPackets = 0;
|
m_sentPackets = 0;
|
||||||
m_receivedPackets = 0;
|
m_receivedPackets = 0;
|
||||||
|
m_sentMessages = 0;
|
||||||
|
m_receivedMessages = 0;
|
||||||
|
m_receivedFragments = 0;
|
||||||
m_sentBytes = 0;
|
m_sentBytes = 0;
|
||||||
m_receivedBytes = 0;
|
m_receivedBytes = 0;
|
||||||
|
m_resentMessagesDueToDelay = 0;
|
||||||
|
m_resentMessagesDueToHole = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the number of sent packets for this connection
|
/// Gets the number of sent packets for this connection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int SentPackets { get { return m_sentPackets; } }
|
public long SentPackets { get { return m_sentPackets; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the number of received packets for this connection
|
/// Gets the number of received packets for this connection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ReceivedPackets { get { return m_receivedPackets; } }
|
public long ReceivedPackets { get { return m_receivedPackets; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the number of sent bytes for this connection
|
/// Gets the number of sent bytes for this connection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int SentBytes { get { return m_sentBytes; } }
|
public long SentBytes { get { return m_sentBytes; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the number of received bytes for this connection
|
/// Gets the number of received bytes for this connection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ReceivedBytes { get { return m_receivedBytes; } }
|
public long ReceivedBytes { get { return m_receivedBytes; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of sent messages for this connection
|
||||||
|
/// </summary>
|
||||||
|
public long SentMessages { get { return m_sentMessages; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of received messages for this connection
|
||||||
|
/// </summary>
|
||||||
|
public long ReceivedMessages { get { return m_receivedMessages; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the number of resent reliable messages for this connection
|
/// Gets the number of resent reliable messages for this connection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ResentMessages { get { return m_resentMessagesDueToHole + m_resentMessagesDueToDelay; } }
|
public long ResentMessages { get { return m_resentMessagesDueToHole + m_resentMessagesDueToDelay; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of dropped messages for this connection
|
||||||
|
/// </summary>
|
||||||
|
public long DroppedMessages { get { return m_droppedMessages; } }
|
||||||
|
|
||||||
// public double LastSendRespondedTo { get { return m_connection.m_lastSendRespondedTo; } }
|
// public double LastSendRespondedTo { get { return m_connection.m_lastSendRespondedTo; } }
|
||||||
|
|
||||||
#if USE_RELEASE_STATISTICS
|
#if !USE_RELEASE_STATISTICS
|
||||||
|
[Conditional("DEBUG")]
|
||||||
|
#endif
|
||||||
internal void PacketSent(int numBytes, int numMessages)
|
internal void PacketSent(int numBytes, int numMessages)
|
||||||
{
|
{
|
||||||
NetException.Assert(numBytes > 0 && numMessages > 0);
|
NetException.Assert(numBytes > 0 && numMessages > 0);
|
||||||
@@ -101,37 +125,22 @@ namespace Lidgren.Network
|
|||||||
m_sentBytes += numBytes;
|
m_sentBytes += numBytes;
|
||||||
m_sentMessages += numMessages;
|
m_sentMessages += numMessages;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
[Conditional("DEBUG")]
|
|
||||||
internal void PacketSent(int numBytes, int numMessages)
|
|
||||||
{
|
|
||||||
NetException.Assert(numBytes > 0 && numMessages > 0);
|
|
||||||
m_sentPackets++;
|
|
||||||
m_sentBytes += numBytes;
|
|
||||||
m_sentMessages += numMessages;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if USE_RELEASE_STATISTICS
|
#if !USE_RELEASE_STATISTICS
|
||||||
internal void PacketReceived(int numBytes, int numMessages)
|
[Conditional("DEBUG")]
|
||||||
|
#endif
|
||||||
|
internal void PacketReceived(int numBytes, int numMessages, int numFragments)
|
||||||
{
|
{
|
||||||
NetException.Assert(numBytes > 0 && numMessages > 0);
|
NetException.Assert(numBytes > 0 && numMessages > 0);
|
||||||
m_receivedPackets++;
|
m_receivedPackets++;
|
||||||
m_receivedBytes += numBytes;
|
m_receivedBytes += numBytes;
|
||||||
m_receivedMessages += numMessages;
|
m_receivedMessages += numMessages;
|
||||||
|
m_receivedFragments += numFragments;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
[Conditional("DEBUG")]
|
|
||||||
internal void PacketReceived(int numBytes, int numMessages)
|
|
||||||
{
|
|
||||||
NetException.Assert(numBytes > 0 && numMessages > 0);
|
|
||||||
m_receivedPackets++;
|
|
||||||
m_receivedBytes += numBytes;
|
|
||||||
m_receivedMessages += numMessages;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if USE_RELEASE_STATISTICS
|
#if !USE_RELEASE_STATISTICS
|
||||||
|
[Conditional("DEBUG")]
|
||||||
|
#endif
|
||||||
internal void MessageResent(MessageResendReason reason)
|
internal void MessageResent(MessageResendReason reason)
|
||||||
{
|
{
|
||||||
if (reason == MessageResendReason.Delay)
|
if (reason == MessageResendReason.Delay)
|
||||||
@@ -139,16 +148,14 @@ namespace Lidgren.Network
|
|||||||
else
|
else
|
||||||
m_resentMessagesDueToHole++;
|
m_resentMessagesDueToHole++;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
|
#if !USE_RELEASE_STATISTICS
|
||||||
[Conditional("DEBUG")]
|
[Conditional("DEBUG")]
|
||||||
internal void MessageResent(MessageResendReason reason)
|
|
||||||
{
|
|
||||||
if (reason == MessageResendReason.Delay)
|
|
||||||
m_resentMessagesDueToDelay++;
|
|
||||||
else
|
|
||||||
m_resentMessagesDueToHole++;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
internal void MessageDropped()
|
||||||
|
{
|
||||||
|
m_droppedMessages++;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a string that represents this object
|
/// Returns a string that represents this object
|
||||||
@@ -157,12 +164,14 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
StringBuilder bdr = new StringBuilder();
|
StringBuilder bdr = new StringBuilder();
|
||||||
//bdr.AppendLine("Average roundtrip time: " + NetTime.ToReadable(m_connection.m_averageRoundtripTime));
|
//bdr.AppendLine("Average roundtrip time: " + NetTime.ToReadable(m_connection.m_averageRoundtripTime));
|
||||||
|
bdr.AppendLine("Current MTU: " + m_connection.m_currentMTU);
|
||||||
bdr.AppendLine("Sent " + m_sentBytes + " bytes in " + m_sentMessages + " messages in " + m_sentPackets + " packets");
|
bdr.AppendLine("Sent " + m_sentBytes + " bytes in " + m_sentMessages + " messages in " + m_sentPackets + " packets");
|
||||||
bdr.AppendLine("Received " + m_receivedBytes + " bytes in " + m_receivedMessages + " messages in " + m_receivedPackets + " packets");
|
bdr.AppendLine("Received " + m_receivedBytes + " bytes in " + m_receivedMessages + " messages (of which " + m_receivedFragments + " fragments) in " + m_receivedPackets + " packets");
|
||||||
|
bdr.AppendLine("Dropped " + m_droppedMessages + " messages (dupes/late/early)");
|
||||||
|
|
||||||
if (m_resentMessagesDueToDelay > 0)
|
if (m_resentMessagesDueToDelay > 0)
|
||||||
bdr.AppendLine("Resent messages (delay): " + m_resentMessagesDueToDelay);
|
bdr.AppendLine("Resent messages (delay): " + m_resentMessagesDueToDelay);
|
||||||
if (m_resentMessagesDueToDelay > 0)
|
if (m_resentMessagesDueToHole > 0)
|
||||||
bdr.AppendLine("Resent messages (holes): " + m_resentMessagesDueToHole);
|
bdr.AppendLine("Resent messages (holes): " + m_resentMessagesDueToHole);
|
||||||
|
|
||||||
int numUnsent = 0;
|
int numUnsent = 0;
|
||||||
@@ -171,7 +180,7 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
if (sendChan == null)
|
if (sendChan == null)
|
||||||
continue;
|
continue;
|
||||||
numUnsent += sendChan.m_queuedSends.Count;
|
numUnsent += sendChan.QueuedSendsCount;
|
||||||
|
|
||||||
var relSendChan = sendChan as NetReliableSenderChannel;
|
var relSendChan = sendChan as NetReliableSenderChannel;
|
||||||
if (relSendChan != null)
|
if (relSendChan != null)
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Exception thrown in the Lidgren Network Library
|
/// Exception thrown in the Lidgren Network Library
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Serializable]
|
|
||||||
public sealed class NetException : Exception
|
public sealed class NetException : Exception
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -52,14 +51,6 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// NetException constructor
|
|
||||||
/// </summary>
|
|
||||||
private NetException(SerializationInfo info, StreamingContext context)
|
|
||||||
: base(info, context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Throws an exception, in DEBUG only, if first parameter is false
|
/// Throws an exception, in DEBUG only, if first parameter is false
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ using System;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
#if !__NOIPENDPOINT__
|
||||||
|
using NetEndPoint = System.Net.IPEndPoint;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -29,7 +33,7 @@ namespace Lidgren.Network
|
|||||||
public sealed class NetIncomingMessage : NetBuffer
|
public sealed class NetIncomingMessage : NetBuffer
|
||||||
{
|
{
|
||||||
internal NetIncomingMessageType m_incomingMessageType;
|
internal NetIncomingMessageType m_incomingMessageType;
|
||||||
internal IPEndPoint m_senderEndPoint;
|
internal NetEndPoint m_senderEndPoint;
|
||||||
internal NetConnection m_senderConnection;
|
internal NetConnection m_senderConnection;
|
||||||
internal int m_sequenceNumber;
|
internal int m_sequenceNumber;
|
||||||
internal NetMessageType m_receivedMessageType;
|
internal NetMessageType m_receivedMessageType;
|
||||||
@@ -52,9 +56,9 @@ namespace Lidgren.Network
|
|||||||
public int SequenceChannel { get { return (int)m_receivedMessageType - (int)NetUtility.GetDeliveryMethod(m_receivedMessageType); } }
|
public int SequenceChannel { get { return (int)m_receivedMessageType - (int)NetUtility.GetDeliveryMethod(m_receivedMessageType); } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// IPEndPoint of sender, if any
|
/// endpoint of sender, if any
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IPEndPoint SenderEndPoint { get { return m_senderEndPoint; } }
|
public NetEndPoint SenderEndPoint { get { return m_senderEndPoint; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// NetConnection of sender, if any
|
/// NetConnection of sender, if any
|
||||||
@@ -90,7 +94,7 @@ namespace Lidgren.Network
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="encryption">The encryption algorithm used to encrypt the message</param>
|
/// <param name="encryption">The encryption algorithm used to encrypt the message</param>
|
||||||
/// <returns>true on success</returns>
|
/// <returns>true on success</returns>
|
||||||
public bool Decrypt(INetEncryption encryption)
|
public bool Decrypt(NetEncryption encryption)
|
||||||
{
|
{
|
||||||
return encryption.Decrypt(this);
|
return encryption.Decrypt(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
#if !__NOIPENDPOINT__
|
||||||
|
using NetEndPoint = System.Net.IPEndPoint;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
@@ -10,29 +15,31 @@ namespace Lidgren.Network
|
|||||||
/// Send NetIntroduction to hostExternal and clientExternal; introducing client to host
|
/// Send NetIntroduction to hostExternal and clientExternal; introducing client to host
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Introduce(
|
public void Introduce(
|
||||||
IPEndPoint hostInternal,
|
NetEndPoint hostInternal,
|
||||||
IPEndPoint hostExternal,
|
NetEndPoint hostExternal,
|
||||||
IPEndPoint clientInternal,
|
NetEndPoint clientInternal,
|
||||||
IPEndPoint clientExternal,
|
NetEndPoint clientExternal,
|
||||||
string token)
|
string token)
|
||||||
{
|
{
|
||||||
// send message to client
|
// send message to client
|
||||||
NetOutgoingMessage msg = CreateMessage(10 + token.Length + 1);
|
NetOutgoingMessage um = CreateMessage(10 + token.Length + 1);
|
||||||
msg.m_messageType = NetMessageType.NatIntroduction;
|
um.m_messageType = NetMessageType.NatIntroduction;
|
||||||
msg.Write((byte)0);
|
um.Write((byte)0);
|
||||||
msg.Write(hostInternal);
|
um.Write(hostInternal);
|
||||||
msg.Write(hostExternal);
|
um.Write(hostExternal);
|
||||||
msg.Write(token);
|
um.Write(token);
|
||||||
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(clientExternal, msg));
|
Interlocked.Increment(ref um.m_recyclingCount);
|
||||||
|
m_unsentUnconnectedMessages.Enqueue(new NetTuple<NetEndPoint, NetOutgoingMessage>(clientExternal, um));
|
||||||
|
|
||||||
// send message to host
|
// send message to host
|
||||||
msg = CreateMessage(10 + token.Length + 1);
|
um = CreateMessage(10 + token.Length + 1);
|
||||||
msg.m_messageType = NetMessageType.NatIntroduction;
|
um.m_messageType = NetMessageType.NatIntroduction;
|
||||||
msg.Write((byte)1);
|
um.Write((byte)1);
|
||||||
msg.Write(clientInternal);
|
um.Write(clientInternal);
|
||||||
msg.Write(clientExternal);
|
um.Write(clientExternal);
|
||||||
msg.Write(token);
|
um.Write(token);
|
||||||
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(hostExternal, msg));
|
Interlocked.Increment(ref um.m_recyclingCount);
|
||||||
|
m_unsentUnconnectedMessages.Enqueue(new NetTuple<NetEndPoint, NetOutgoingMessage>(hostExternal, um));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -46,8 +53,8 @@ namespace Lidgren.Network
|
|||||||
NetIncomingMessage tmp = SetupReadHelperMessage(ptr, 1000); // never mind length
|
NetIncomingMessage tmp = SetupReadHelperMessage(ptr, 1000); // never mind length
|
||||||
|
|
||||||
byte hostByte = tmp.ReadByte();
|
byte hostByte = tmp.ReadByte();
|
||||||
IPEndPoint remoteInternal = tmp.ReadIPEndPoint();
|
NetEndPoint remoteInternal = tmp.ReadIPEndPoint();
|
||||||
IPEndPoint remoteExternal = tmp.ReadIPEndPoint();
|
NetEndPoint remoteExternal = tmp.ReadIPEndPoint();
|
||||||
string token = tmp.ReadString();
|
string token = tmp.ReadString();
|
||||||
bool isHost = (hostByte != 0);
|
bool isHost = (hostByte != 0);
|
||||||
|
|
||||||
@@ -63,20 +70,25 @@ namespace Lidgren.Network
|
|||||||
punch.m_messageType = NetMessageType.NatPunchMessage;
|
punch.m_messageType = NetMessageType.NatPunchMessage;
|
||||||
punch.Write(hostByte);
|
punch.Write(hostByte);
|
||||||
punch.Write(token);
|
punch.Write(token);
|
||||||
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(remoteInternal, punch));
|
Interlocked.Increment(ref punch.m_recyclingCount);
|
||||||
|
m_unsentUnconnectedMessages.Enqueue(new NetTuple<NetEndPoint, NetOutgoingMessage>(remoteInternal, punch));
|
||||||
|
LogDebug("NAT punch sent to " + remoteInternal);
|
||||||
|
|
||||||
// send external punch
|
// send external punch
|
||||||
punch = CreateMessage(1);
|
punch = CreateMessage(1);
|
||||||
punch.m_messageType = NetMessageType.NatPunchMessage;
|
punch.m_messageType = NetMessageType.NatPunchMessage;
|
||||||
punch.Write(hostByte);
|
punch.Write(hostByte);
|
||||||
punch.Write(token);
|
punch.Write(token);
|
||||||
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(remoteExternal, punch));
|
Interlocked.Increment(ref punch.m_recyclingCount);
|
||||||
|
m_unsentUnconnectedMessages.Enqueue(new NetTuple<NetEndPoint, NetOutgoingMessage>(remoteExternal, punch));
|
||||||
|
LogDebug("NAT punch sent to " + remoteExternal);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when receiving a NatPunchMessage from a remote endpoint
|
/// Called when receiving a NatPunchMessage from a remote endpoint
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void HandleNatPunch(int ptr, IPEndPoint senderEndPoint)
|
private void HandleNatPunch(int ptr, NetEndPoint senderEndPoint)
|
||||||
{
|
{
|
||||||
NetIncomingMessage tmp = SetupReadHelperMessage(ptr, 1000); // never mind length
|
NetIncomingMessage tmp = SetupReadHelperMessage(ptr, 1000); // never mind length
|
||||||
|
|
||||||
@@ -92,7 +104,7 @@ namespace Lidgren.Network
|
|||||||
LogDebug("NAT punch received from " + senderEndPoint + " we're client, so we've succeeded - token is " + token);
|
LogDebug("NAT punch received from " + senderEndPoint + " we're client, so we've succeeded - token is " + token);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Release punch success to client; enabling him to Connect() to msg.SenderIPEndPoint if token is ok
|
// Release punch success to client; enabling him to Connect() to msg.Sender if token is ok
|
||||||
//
|
//
|
||||||
NetIncomingMessage punchSuccess = CreateIncomingMessage(NetIncomingMessageType.NatIntroductionSuccess, 10);
|
NetIncomingMessage punchSuccess = CreateIncomingMessage(NetIncomingMessageType.NatIntroductionSuccess, 10);
|
||||||
punchSuccess.m_senderEndPoint = senderEndPoint;
|
punchSuccess.m_senderEndPoint = senderEndPoint;
|
||||||
@@ -104,7 +116,8 @@ namespace Lidgren.Network
|
|||||||
punch.m_messageType = NetMessageType.NatPunchMessage;
|
punch.m_messageType = NetMessageType.NatPunchMessage;
|
||||||
punch.Write((byte)0);
|
punch.Write((byte)0);
|
||||||
punch.Write(token);
|
punch.Write(token);
|
||||||
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(senderEndPoint, punch));
|
Interlocked.Increment(ref punch.m_recyclingCount);
|
||||||
|
m_unsentUnconnectedMessages.Enqueue(new NetTuple<NetEndPoint, NetOutgoingMessage>(senderEndPoint, punch));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,13 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
internal NetMessageType m_messageType;
|
internal NetMessageType m_messageType;
|
||||||
internal bool m_isSent;
|
internal bool m_isSent;
|
||||||
|
|
||||||
|
// Recycling count is:
|
||||||
|
// * incremented for each recipient on send
|
||||||
|
// * incremented, when reliable, in SenderChannel.ExecuteSend()
|
||||||
|
// * decremented (both reliable and unreliable) in NetConnection.QueueSendMessage()
|
||||||
|
// * decremented, when reliable, in SenderChannel.DestoreMessage()
|
||||||
|
// ... when it reaches zero it can be recycled
|
||||||
internal int m_recyclingCount;
|
internal int m_recyclingCount;
|
||||||
|
|
||||||
internal int m_fragmentGroup; // which group of fragments ths belongs to
|
internal int m_fragmentGroup; // which group of fragments ths belongs to
|
||||||
@@ -46,7 +53,7 @@ namespace Lidgren.Network
|
|||||||
m_messageType = NetMessageType.LibraryError;
|
m_messageType = NetMessageType.LibraryError;
|
||||||
m_bitLength = 0;
|
m_bitLength = 0;
|
||||||
m_isSent = false;
|
m_isSent = false;
|
||||||
m_recyclingCount = 0;
|
NetException.Assert(m_recyclingCount == 0);
|
||||||
m_fragmentGroup = 0;
|
m_fragmentGroup = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +123,7 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Encrypt this message using the provided algorithm; no more writing can be done before sending it or the message will be corrupt!
|
/// Encrypt this message using the provided algorithm; no more writing can be done before sending it or the message will be corrupt!
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Encrypt(INetEncryption encryption)
|
public bool Encrypt(NetEncryption encryption)
|
||||||
{
|
{
|
||||||
return encryption.Encrypt(this);
|
return encryption.Encrypt(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
#if !__NOIPENDPOINT__
|
||||||
|
using NetEndPoint = System.Net.IPEndPoint;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
@@ -10,9 +15,11 @@ namespace Lidgren.Network
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void DiscoverLocalPeers(int serverPort)
|
public void DiscoverLocalPeers(int serverPort)
|
||||||
{
|
{
|
||||||
NetOutgoingMessage om = CreateMessage(0);
|
NetOutgoingMessage um = CreateMessage(0);
|
||||||
om.m_messageType = NetMessageType.Discovery;
|
um.m_messageType = NetMessageType.Discovery;
|
||||||
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(new IPEndPoint(IPAddress.Broadcast, serverPort), om));
|
Interlocked.Increment(ref um.m_recyclingCount);
|
||||||
|
|
||||||
|
m_unsentUnconnectedMessages.Enqueue(new NetTuple<NetEndPoint, NetOutgoingMessage>(new NetEndPoint(NetUtility.GetBroadcastAddress(), serverPort), um));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -20,27 +27,28 @@ namespace Lidgren.Network
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool DiscoverKnownPeer(string host, int serverPort)
|
public bool DiscoverKnownPeer(string host, int serverPort)
|
||||||
{
|
{
|
||||||
IPAddress address = NetUtility.Resolve(host);
|
var address = NetUtility.Resolve(host);
|
||||||
if (address == null)
|
if (address == null)
|
||||||
return false;
|
return false;
|
||||||
DiscoverKnownPeer(new IPEndPoint(address, serverPort));
|
DiscoverKnownPeer(new NetEndPoint(address, serverPort));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Emit a discovery signal to a single known host
|
/// Emit a discovery signal to a single known host
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void DiscoverKnownPeer(IPEndPoint endPoint)
|
public void DiscoverKnownPeer(NetEndPoint endPoint)
|
||||||
{
|
{
|
||||||
NetOutgoingMessage om = CreateMessage(0);
|
NetOutgoingMessage om = CreateMessage(0);
|
||||||
om.m_messageType = NetMessageType.Discovery;
|
om.m_messageType = NetMessageType.Discovery;
|
||||||
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(endPoint, om));
|
om.m_recyclingCount = 1;
|
||||||
|
m_unsentUnconnectedMessages.Enqueue(new NetTuple<NetEndPoint, NetOutgoingMessage>(endPoint, om));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Send a discovery response message
|
/// Send a discovery response message
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SendDiscoveryResponse(NetOutgoingMessage msg, IPEndPoint recipient)
|
public void SendDiscoveryResponse(NetOutgoingMessage msg, NetEndPoint recipient)
|
||||||
{
|
{
|
||||||
if (recipient == null)
|
if (recipient == null)
|
||||||
throw new ArgumentNullException("recipient");
|
throw new ArgumentNullException("recipient");
|
||||||
@@ -54,7 +62,8 @@ namespace Lidgren.Network
|
|||||||
throw new NetException("Cannot send discovery message larger than MTU (currently " + m_configuration.MaximumTransmissionUnit + " bytes)");
|
throw new NetException("Cannot send discovery message larger than MTU (currently " + m_configuration.MaximumTransmissionUnit + " bytes)");
|
||||||
|
|
||||||
msg.m_messageType = NetMessageType.DiscoveryResponse;
|
msg.m_messageType = NetMessageType.DiscoveryResponse;
|
||||||
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(recipient, msg));
|
Interlocked.Increment(ref msg.m_recyclingCount);
|
||||||
|
m_unsentUnconnectedMessages.Enqueue(new NetTuple<NetEndPoint, NetOutgoingMessage>(recipient, msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
internal class ReceivedFragmentGroup
|
internal class ReceivedFragmentGroup
|
||||||
{
|
{
|
||||||
public float LastReceived;
|
//public float LastReceived;
|
||||||
public byte[] Data;
|
public byte[] Data;
|
||||||
public NetBitVector ReceivedChunks;
|
public NetBitVector ReceivedChunks;
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@ namespace Lidgren.Network
|
|||||||
private Dictionary<NetConnection, Dictionary<int, ReceivedFragmentGroup>> m_receivedFragmentGroups;
|
private Dictionary<NetConnection, Dictionary<int, ReceivedFragmentGroup>> m_receivedFragmentGroups;
|
||||||
|
|
||||||
// on user thread
|
// on user thread
|
||||||
private void SendFragmentedMessage(NetOutgoingMessage msg, IList<NetConnection> recipients, NetDeliveryMethod method, int sequenceChannel)
|
private NetSendResult SendFragmentedMessage(NetOutgoingMessage msg, IList<NetConnection> recipients, NetDeliveryMethod method, int sequenceChannel)
|
||||||
{
|
{
|
||||||
// Note: this group id is PER SENDING/NetPeer; ie. same id is sent to all recipients;
|
// Note: this group id is PER SENDING/NetPeer; ie. same id is sent to all recipients;
|
||||||
// this should be ok however; as long as recipients differentiate between same id but different sender
|
// this should be ok however; as long as recipients differentiate between same id but different sender
|
||||||
@@ -44,11 +44,13 @@ namespace Lidgren.Network
|
|||||||
if (numChunks * bytesPerChunk < totalBytes)
|
if (numChunks * bytesPerChunk < totalBytes)
|
||||||
numChunks++;
|
numChunks++;
|
||||||
|
|
||||||
|
NetSendResult retval = NetSendResult.Sent;
|
||||||
|
|
||||||
int bitsPerChunk = bytesPerChunk * 8;
|
int bitsPerChunk = bytesPerChunk * 8;
|
||||||
int bitsLeft = msg.LengthBits;
|
int bitsLeft = msg.LengthBits;
|
||||||
for (int i = 0; i < numChunks; i++)
|
for (int i = 0; i < numChunks; i++)
|
||||||
{
|
{
|
||||||
NetOutgoingMessage chunk = CreateMessage(mtu);
|
NetOutgoingMessage chunk = CreateMessage(0);
|
||||||
|
|
||||||
chunk.m_bitLength = (bitsLeft > bitsPerChunk ? bitsPerChunk : bitsLeft);
|
chunk.m_bitLength = (bitsLeft > bitsPerChunk ? bitsPerChunk : bitsLeft);
|
||||||
chunk.m_data = msg.m_data;
|
chunk.m_data = msg.m_data;
|
||||||
@@ -63,12 +65,18 @@ namespace Lidgren.Network
|
|||||||
Interlocked.Add(ref chunk.m_recyclingCount, recipients.Count);
|
Interlocked.Add(ref chunk.m_recyclingCount, recipients.Count);
|
||||||
|
|
||||||
foreach (NetConnection recipient in recipients)
|
foreach (NetConnection recipient in recipients)
|
||||||
recipient.EnqueueMessage(chunk, method, sequenceChannel);
|
{
|
||||||
|
var res = recipient.EnqueueMessage(chunk, method, sequenceChannel);
|
||||||
|
if (res == NetSendResult.Dropped)
|
||||||
|
Interlocked.Decrement(ref chunk.m_recyclingCount);
|
||||||
|
if ((int)res > (int)retval)
|
||||||
|
retval = res; // return "worst" result
|
||||||
|
}
|
||||||
|
|
||||||
bitsLeft -= bitsPerChunk;
|
bitsLeft -= bitsPerChunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleReleasedFragment(NetIncomingMessage im)
|
private void HandleReleasedFragment(NetIncomingMessage im)
|
||||||
@@ -126,7 +134,7 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
|
|
||||||
info.ReceivedChunks[chunkNumber] = true;
|
info.ReceivedChunks[chunkNumber] = true;
|
||||||
info.LastReceived = (float)NetTime.Now;
|
//info.LastReceived = (float)NetTime.Now;
|
||||||
|
|
||||||
// copy to data
|
// copy to data
|
||||||
int offset = (chunkNumber * chunkByteSize);
|
int offset = (chunkNumber * chunkByteSize);
|
||||||
|
|||||||
+179
-122
@@ -1,8 +1,4 @@
|
|||||||
#if !__ANDROID__ && !IOS
|
using System;
|
||||||
#define IS_MAC_AVAILABLE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@@ -10,6 +6,10 @@ using System.Security.Cryptography;
|
|||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
#if !__NOIPENDPOINT__
|
||||||
|
using NetEndPoint = System.Net.IPEndPoint;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
public partial class NetPeer
|
public partial class NetPeer
|
||||||
@@ -24,13 +24,15 @@ namespace Lidgren.Network
|
|||||||
private object m_initializeLock = new object();
|
private object m_initializeLock = new object();
|
||||||
private uint m_frameCounter;
|
private uint m_frameCounter;
|
||||||
private double m_lastHeartbeat;
|
private double m_lastHeartbeat;
|
||||||
|
private double m_lastSocketBind = float.MinValue;
|
||||||
private NetUPnP m_upnp;
|
private NetUPnP m_upnp;
|
||||||
|
internal bool m_needFlushSendQueue;
|
||||||
|
|
||||||
internal readonly NetPeerConfiguration m_configuration;
|
internal readonly NetPeerConfiguration m_configuration;
|
||||||
private readonly NetQueue<NetIncomingMessage> m_releasedIncomingMessages;
|
private readonly NetQueue<NetIncomingMessage> m_releasedIncomingMessages;
|
||||||
internal readonly NetQueue<NetTuple<IPEndPoint, NetOutgoingMessage>> m_unsentUnconnectedMessages;
|
internal readonly NetQueue<NetTuple<NetEndPoint, NetOutgoingMessage>> m_unsentUnconnectedMessages;
|
||||||
|
|
||||||
internal Dictionary<IPEndPoint, NetConnection> m_handshakes;
|
internal Dictionary<NetEndPoint, NetConnection> m_handshakes;
|
||||||
|
|
||||||
internal readonly NetPeerStatistics m_statistics;
|
internal readonly NetPeerStatistics m_statistics;
|
||||||
internal long m_uniqueIdentifier;
|
internal long m_uniqueIdentifier;
|
||||||
@@ -47,13 +49,15 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Call this to register a callback for when a new message arrives
|
/// Call this to register a callback for when a new message arrives
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void RegisterReceivedCallback(SendOrPostCallback callback)
|
public void RegisterReceivedCallback(SendOrPostCallback callback, SynchronizationContext syncContext = null)
|
||||||
{
|
{
|
||||||
if (SynchronizationContext.Current == null)
|
if (syncContext == null)
|
||||||
|
syncContext = SynchronizationContext.Current;
|
||||||
|
if (syncContext == null)
|
||||||
throw new NetException("Need a SynchronizationContext to register callback on correct thread!");
|
throw new NetException("Need a SynchronizationContext to register callback on correct thread!");
|
||||||
if (m_receiveCallbacks == null)
|
if (m_receiveCallbacks == null)
|
||||||
m_receiveCallbacks = new List<NetTuple<SynchronizationContext, SendOrPostCallback>>();
|
m_receiveCallbacks = new List<NetTuple<SynchronizationContext, SendOrPostCallback>>();
|
||||||
m_receiveCallbacks.Add(new NetTuple<SynchronizationContext, SendOrPostCallback>(SynchronizationContext.Current, callback));
|
m_receiveCallbacks.Add(new NetTuple<SynchronizationContext, SendOrPostCallback>(syncContext, callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -63,7 +67,17 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
if (m_receiveCallbacks == null)
|
if (m_receiveCallbacks == null)
|
||||||
return;
|
return;
|
||||||
m_receiveCallbacks.Remove(new NetTuple<SynchronizationContext, SendOrPostCallback>(SynchronizationContext.Current, callback));
|
|
||||||
|
// remove all callbacks regardless of sync context
|
||||||
|
RestartRemoveCallbacks:
|
||||||
|
for (int i = 0; i < m_receiveCallbacks.Count; i++)
|
||||||
|
{
|
||||||
|
if (m_receiveCallbacks[i].Item2.Equals(callback))
|
||||||
|
{
|
||||||
|
m_receiveCallbacks.RemoveAt(i);
|
||||||
|
goto RestartRemoveCallbacks;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (m_receiveCallbacks.Count < 1)
|
if (m_receiveCallbacks.Count < 1)
|
||||||
m_receiveCallbacks = null;
|
m_receiveCallbacks = null;
|
||||||
}
|
}
|
||||||
@@ -86,10 +100,59 @@ namespace Lidgren.Network
|
|||||||
if (m_receiveCallbacks != null)
|
if (m_receiveCallbacks != null)
|
||||||
{
|
{
|
||||||
foreach (var tuple in m_receiveCallbacks)
|
foreach (var tuple in m_receiveCallbacks)
|
||||||
tuple.Item1.Post(tuple.Item2, this);
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
tuple.Item1.Post(tuple.Item2, this);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogWarning("Receive callback exception:" + ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void BindSocket(bool reBind)
|
||||||
|
{
|
||||||
|
double now = NetTime.Now;
|
||||||
|
if (now - m_lastSocketBind < 1.0)
|
||||||
|
{
|
||||||
|
LogDebug("Suppressed socket rebind; last bound " + (now - m_lastSocketBind) + " seconds ago");
|
||||||
|
return; // only allow rebind once every second
|
||||||
|
}
|
||||||
|
m_lastSocketBind = now;
|
||||||
|
|
||||||
|
if (m_socket == null)
|
||||||
|
m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||||
|
|
||||||
|
if (reBind)
|
||||||
|
m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, (int)1);
|
||||||
|
|
||||||
|
m_socket.ReceiveBufferSize = m_configuration.ReceiveBufferSize;
|
||||||
|
m_socket.SendBufferSize = m_configuration.SendBufferSize;
|
||||||
|
m_socket.Blocking = false;
|
||||||
|
|
||||||
|
var ep = (EndPoint)new NetEndPoint(m_configuration.LocalAddress, reBind ? m_listenPort : m_configuration.Port);
|
||||||
|
m_socket.Bind(ep);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const uint IOC_IN = 0x80000000;
|
||||||
|
const uint IOC_VENDOR = 0x18000000;
|
||||||
|
uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
|
||||||
|
m_socket.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignore; SIO_UDP_CONNRESET not supported on this platform
|
||||||
|
}
|
||||||
|
|
||||||
|
var boundEp = m_socket.LocalEndPoint as NetEndPoint;
|
||||||
|
LogDebug("Socket bound to " + boundEp + ": " + m_socket.IsBound);
|
||||||
|
m_listenPort = boundEp.Port;
|
||||||
|
}
|
||||||
|
|
||||||
private void InitializeNetwork()
|
private void InitializeNetwork()
|
||||||
{
|
{
|
||||||
lock (m_initializeLock)
|
lock (m_initializeLock)
|
||||||
@@ -109,65 +172,21 @@ namespace Lidgren.Network
|
|||||||
m_handshakes.Clear();
|
m_handshakes.Clear();
|
||||||
|
|
||||||
// bind to socket
|
// bind to socket
|
||||||
IPEndPoint iep = null;
|
BindSocket(false);
|
||||||
|
|
||||||
iep = new IPEndPoint(m_configuration.LocalAddress, m_configuration.Port);
|
|
||||||
EndPoint ep = (EndPoint)iep;
|
|
||||||
|
|
||||||
m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
|
||||||
m_socket.ReceiveBufferSize = m_configuration.ReceiveBufferSize;
|
|
||||||
m_socket.SendBufferSize = m_configuration.SendBufferSize;
|
|
||||||
m_socket.Blocking = false;
|
|
||||||
m_socket.Bind(ep);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
const uint IOC_IN = 0x80000000;
|
|
||||||
const uint IOC_VENDOR = 0x18000000;
|
|
||||||
uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
|
|
||||||
m_socket.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignore; SIO_UDP_CONNRESET not supported on this platform
|
|
||||||
}
|
|
||||||
|
|
||||||
IPEndPoint boundEp = m_socket.LocalEndPoint as IPEndPoint;
|
|
||||||
LogDebug("Socket bound to " + boundEp + ": " + m_socket.IsBound);
|
|
||||||
m_listenPort = boundEp.Port;
|
|
||||||
|
|
||||||
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];
|
||||||
m_readHelperMessage = new NetIncomingMessage(NetIncomingMessageType.Error);
|
m_readHelperMessage = new NetIncomingMessage(NetIncomingMessageType.Error);
|
||||||
m_readHelperMessage.m_data = m_receiveBuffer;
|
m_readHelperMessage.m_data = m_receiveBuffer;
|
||||||
|
|
||||||
byte[] macBytes = new byte[8];
|
byte[] macBytes = NetUtility.GetMacAddressBytes();
|
||||||
NetRandom.Instance.NextBytes(macBytes);
|
|
||||||
|
|
||||||
#if IS_MAC_AVAILABLE
|
var boundEp = m_socket.LocalEndPoint as NetEndPoint;
|
||||||
try
|
|
||||||
{
|
|
||||||
System.Net.NetworkInformation.PhysicalAddress pa = NetUtility.GetMacAddress();
|
|
||||||
if (pa != null)
|
|
||||||
{
|
|
||||||
macBytes = pa.GetAddressBytes();
|
|
||||||
LogVerbose("Mac address is " + NetUtility.ToHexString(macBytes));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogWarning("Failed to get Mac address");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (NotSupportedException)
|
|
||||||
{
|
|
||||||
// not supported; lets just keep the random bytes set above
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
byte[] epBytes = BitConverter.GetBytes(boundEp.GetHashCode());
|
byte[] epBytes = BitConverter.GetBytes(boundEp.GetHashCode());
|
||||||
byte[] combined = new byte[epBytes.Length + macBytes.Length];
|
byte[] combined = new byte[epBytes.Length + macBytes.Length];
|
||||||
Array.Copy(epBytes, 0, combined, 0, epBytes.Length);
|
Array.Copy(epBytes, 0, combined, 0, epBytes.Length);
|
||||||
Array.Copy(macBytes, 0, combined, epBytes.Length, macBytes.Length);
|
Array.Copy(macBytes, 0, combined, epBytes.Length, macBytes.Length);
|
||||||
m_uniqueIdentifier = BitConverter.ToInt64(SHA1.Create().ComputeHash(combined), 0);
|
m_uniqueIdentifier = BitConverter.ToInt64(NetUtility.ComputeSHAHash(combined), 0);
|
||||||
|
|
||||||
m_status = NetPeerStatus.Running;
|
m_status = NetPeerStatus.Running;
|
||||||
}
|
}
|
||||||
@@ -213,26 +232,26 @@ namespace Lidgren.Network
|
|||||||
foreach (var conn in m_connections)
|
foreach (var conn in m_connections)
|
||||||
if (conn != null)
|
if (conn != null)
|
||||||
list.Add(conn);
|
list.Add(conn);
|
||||||
|
|
||||||
lock (m_handshakes)
|
|
||||||
{
|
|
||||||
foreach (var hs in m_handshakes.Values)
|
|
||||||
if (hs != null)
|
|
||||||
list.Add(hs);
|
|
||||||
|
|
||||||
// shut down connections
|
|
||||||
foreach (NetConnection conn in list)
|
|
||||||
conn.Shutdown(m_shutdownReason);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lock (m_handshakes)
|
||||||
|
{
|
||||||
|
foreach (var hs in m_handshakes.Values)
|
||||||
|
if (hs != null && list.Contains(hs) == false)
|
||||||
|
list.Add(hs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// shut down connections
|
||||||
|
foreach (NetConnection conn in list)
|
||||||
|
conn.Shutdown(m_shutdownReason);
|
||||||
|
|
||||||
FlushDelayedPackets();
|
FlushDelayedPackets();
|
||||||
|
|
||||||
// one final heartbeat, will send stuff and do disconnect
|
// one final heartbeat, will send stuff and do disconnect
|
||||||
Heartbeat();
|
Heartbeat();
|
||||||
|
|
||||||
Thread.Sleep(10);
|
NetUtility.Sleep(10);
|
||||||
|
|
||||||
lock (m_initializeLock)
|
lock (m_initializeLock)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -243,14 +262,19 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
m_socket.Shutdown(SocketShutdown.Receive);
|
m_socket.Shutdown(SocketShutdown.Receive);
|
||||||
}
|
}
|
||||||
catch { }
|
catch(Exception ex)
|
||||||
m_socket.Close(2); // 2 seconds timeout
|
{
|
||||||
}
|
LogDebug("Socket.Shutdown exception: " + ex.ToString());
|
||||||
if (m_messageReceivedEvent != null)
|
}
|
||||||
{
|
|
||||||
m_messageReceivedEvent.Set();
|
try
|
||||||
m_messageReceivedEvent.Close();
|
{
|
||||||
m_messageReceivedEvent = null;
|
m_socket.Close(2); // 2 seconds timeout
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogDebug("Socket.Close exception: " + ex.ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -258,8 +282,13 @@ namespace Lidgren.Network
|
|||||||
m_socket = null;
|
m_socket = null;
|
||||||
m_status = NetPeerStatus.NotRunning;
|
m_status = NetPeerStatus.NotRunning;
|
||||||
LogDebug("Shutdown complete");
|
LogDebug("Shutdown complete");
|
||||||
|
|
||||||
|
// wake up any threads waiting for server shutdown
|
||||||
|
if (m_messageReceivedEvent != null)
|
||||||
|
m_messageReceivedEvent.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_lastSocketBind = float.MinValue;
|
||||||
m_receiveBuffer = null;
|
m_receiveBuffer = null;
|
||||||
m_sendBuffer = null;
|
m_sendBuffer = null;
|
||||||
m_unsentUnconnectedMessages.Clear();
|
m_unsentUnconnectedMessages.Clear();
|
||||||
@@ -275,10 +304,8 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
VerifyNetworkThread();
|
VerifyNetworkThread();
|
||||||
|
|
||||||
double dnow = NetTime.Now;
|
double now = NetTime.Now;
|
||||||
float now = (float)dnow;
|
double delta = now - m_lastHeartbeat;
|
||||||
|
|
||||||
double delta = dnow - m_lastHeartbeat;
|
|
||||||
|
|
||||||
int maxCHBpS = 1250 - m_connections.Count;
|
int maxCHBpS = 1250 - m_connections.Count;
|
||||||
if (maxCHBpS < 250)
|
if (maxCHBpS < 250)
|
||||||
@@ -286,7 +313,7 @@ namespace Lidgren.Network
|
|||||||
if (delta > (1.0 / (double)maxCHBpS) || delta < 0.0) // max connection heartbeats/second max
|
if (delta > (1.0 / (double)maxCHBpS) || delta < 0.0) // max connection heartbeats/second max
|
||||||
{
|
{
|
||||||
m_frameCounter++;
|
m_frameCounter++;
|
||||||
m_lastHeartbeat = dnow;
|
m_lastHeartbeat = now;
|
||||||
|
|
||||||
// do handshake heartbeats
|
// do handshake heartbeats
|
||||||
if ((m_frameCounter % 3) == 0)
|
if ((m_frameCounter % 3) == 0)
|
||||||
@@ -320,44 +347,51 @@ namespace Lidgren.Network
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// update m_executeFlushSendQueue
|
// update m_executeFlushSendQueue
|
||||||
if (m_configuration.m_autoFlushSendQueue)
|
if (m_configuration.m_autoFlushSendQueue && m_needFlushSendQueue == true)
|
||||||
|
{
|
||||||
m_executeFlushSendQueue = true;
|
m_executeFlushSendQueue = true;
|
||||||
|
m_needFlushSendQueue = false; // a race condition to this variable will simply result in a single superfluous call to FlushSendQueue()
|
||||||
|
}
|
||||||
|
|
||||||
// do connection heartbeats
|
// do connection heartbeats
|
||||||
lock (m_connections)
|
lock (m_connections)
|
||||||
{
|
{
|
||||||
foreach (NetConnection conn in m_connections)
|
for (int i = m_connections.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
|
var conn = m_connections[i];
|
||||||
conn.Heartbeat(now, m_frameCounter);
|
conn.Heartbeat(now, m_frameCounter);
|
||||||
if (conn.m_status == NetConnectionStatus.Disconnected)
|
if (conn.m_status == NetConnectionStatus.Disconnected)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// remove connection
|
// remove connection
|
||||||
//
|
//
|
||||||
m_connections.Remove(conn);
|
m_connections.RemoveAt(i);
|
||||||
m_connectionLookup.Remove(conn.RemoteEndPoint);
|
m_connectionLookup.Remove(conn.RemoteEndPoint);
|
||||||
break; // can't continue iteration here
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_executeFlushSendQueue = false;
|
m_executeFlushSendQueue = false;
|
||||||
|
|
||||||
// send unsent unconnected messages
|
// send unsent unconnected messages
|
||||||
NetTuple<IPEndPoint, NetOutgoingMessage> unsent;
|
NetTuple<NetEndPoint, NetOutgoingMessage> unsent;
|
||||||
while (m_unsentUnconnectedMessages.TryDequeue(out unsent))
|
while (m_unsentUnconnectedMessages.TryDequeue(out unsent))
|
||||||
{
|
{
|
||||||
NetOutgoingMessage om = unsent.Item2;
|
NetOutgoingMessage om = unsent.Item2;
|
||||||
|
|
||||||
bool connReset;
|
|
||||||
int len = om.Encode(m_sendBuffer, 0, 0);
|
int len = om.Encode(m_sendBuffer, 0, 0);
|
||||||
SendPacket(len, unsent.Item1, 1, out connReset);
|
|
||||||
|
|
||||||
Interlocked.Decrement(ref om.m_recyclingCount);
|
Interlocked.Decrement(ref om.m_recyclingCount);
|
||||||
if (om.m_recyclingCount <= 0)
|
if (om.m_recyclingCount <= 0)
|
||||||
Recycle(om);
|
Recycle(om);
|
||||||
|
|
||||||
|
bool connReset;
|
||||||
|
SendPacket(len, unsent.Item1, 1, out connReset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_upnp != null)
|
||||||
|
m_upnp.CheckForDiscoveryTimeout();
|
||||||
|
|
||||||
//
|
//
|
||||||
// read from socket
|
// read from socket
|
||||||
//
|
//
|
||||||
@@ -371,8 +405,7 @@ namespace Lidgren.Network
|
|||||||
// return;
|
// return;
|
||||||
|
|
||||||
// update now
|
// update now
|
||||||
dnow = NetTime.Now;
|
now = NetTime.Now;
|
||||||
now = (float)dnow;
|
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -383,17 +416,24 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
catch (SocketException sx)
|
catch (SocketException sx)
|
||||||
{
|
{
|
||||||
if (sx.SocketErrorCode == SocketError.ConnectionReset)
|
switch (sx.SocketErrorCode)
|
||||||
{
|
{
|
||||||
// connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable"
|
case SocketError.ConnectionReset:
|
||||||
// we should shut down the connection; but m_senderRemote seemingly cannot be trusted, so which connection should we shut down?!
|
// connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable"
|
||||||
// So, what to do?
|
// we should shut down the connection; but m_senderRemote seemingly cannot be trusted, so which connection should we shut down?!
|
||||||
LogWarning("ConnectionReset");
|
// So, what to do?
|
||||||
return;
|
LogWarning("ConnectionReset");
|
||||||
}
|
return;
|
||||||
|
|
||||||
LogWarning(sx.ToString());
|
case SocketError.NotConnected:
|
||||||
return;
|
// socket is unbound; try to rebind it (happens on mobile when process goes to sleep)
|
||||||
|
BindSocket(true);
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
LogWarning("Socket exception: " + sx.ToString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytesReceived < NetConstants.HeaderByteSize)
|
if (bytesReceived < NetConstants.HeaderByteSize)
|
||||||
@@ -401,23 +441,29 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
//LogVerbose("Received " + bytesReceived + " bytes");
|
//LogVerbose("Received " + bytesReceived + " bytes");
|
||||||
|
|
||||||
IPEndPoint ipsender = (IPEndPoint)m_senderRemote;
|
var ipsender = (NetEndPoint)m_senderRemote;
|
||||||
|
|
||||||
if (m_upnp != null && now < m_upnp.m_discoveryResponseDeadline)
|
if (m_upnp != null && now < m_upnp.m_discoveryResponseDeadline && bytesReceived > 32)
|
||||||
{
|
{
|
||||||
// is this an UPnP response?
|
// is this an UPnP response?
|
||||||
try
|
string resp = System.Text.Encoding.UTF8.GetString(m_receiveBuffer, 0, bytesReceived);
|
||||||
|
if (resp.Contains("upnp:rootdevice") || resp.Contains("UPnP/1.0"))
|
||||||
{
|
{
|
||||||
string resp = System.Text.Encoding.ASCII.GetString(m_receiveBuffer, 0, bytesReceived);
|
try
|
||||||
if (resp.Contains("upnp:rootdevice") || resp.Contains("UPnP/1.0"))
|
|
||||||
{
|
{
|
||||||
resp = resp.Substring(resp.ToLower().IndexOf("location:") + 9);
|
resp = resp.Substring(resp.ToLower().IndexOf("location:") + 9);
|
||||||
resp = resp.Substring(0, resp.IndexOf("\r")).Trim();
|
resp = resp.Substring(0, resp.IndexOf("\r")).Trim();
|
||||||
m_upnp.ExtractServiceUrl(resp);
|
m_upnp.ExtractServiceUrl(resp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogDebug("Failed to parse UPnP response: " + ex.ToString());
|
||||||
|
|
||||||
|
// don't try to parse this packet further
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch { }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NetConnection sender = null;
|
NetConnection sender = null;
|
||||||
@@ -427,6 +473,7 @@ namespace Lidgren.Network
|
|||||||
// parse packet into messages
|
// parse packet into messages
|
||||||
//
|
//
|
||||||
int numMessages = 0;
|
int numMessages = 0;
|
||||||
|
int numFragments = 0;
|
||||||
int ptr = 0;
|
int ptr = 0;
|
||||||
while ((bytesReceived - ptr) >= NetConstants.HeaderByteSize)
|
while ((bytesReceived - ptr) >= NetConstants.HeaderByteSize)
|
||||||
{
|
{
|
||||||
@@ -446,6 +493,9 @@ namespace Lidgren.Network
|
|||||||
bool isFragment = ((low & 1) == 1);
|
bool isFragment = ((low & 1) == 1);
|
||||||
ushort sequenceNumber = (ushort)((low >> 1) | (((int)high) << 7));
|
ushort sequenceNumber = (ushort)((low >> 1) | (((int)high) << 7));
|
||||||
|
|
||||||
|
if (isFragment)
|
||||||
|
numFragments++;
|
||||||
|
|
||||||
ushort payloadBitLength = (ushort)(m_receiveBuffer[ptr++] | (m_receiveBuffer[ptr++] << 8));
|
ushort payloadBitLength = (ushort)(m_receiveBuffer[ptr++] | (m_receiveBuffer[ptr++] << 8));
|
||||||
int payloadByteLength = NetUtility.BytesToHoldBits(payloadBitLength);
|
int payloadByteLength = NetUtility.BytesToHoldBits(payloadBitLength);
|
||||||
|
|
||||||
@@ -455,16 +505,20 @@ namespace Lidgren.Network
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tp >= NetMessageType.Unused1 && tp <= NetMessageType.Unused29)
|
||||||
|
{
|
||||||
|
ThrowOrLog("Unexpected NetMessageType: " + tp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
NetException.Assert(tp < NetMessageType.Unused1 || tp > NetMessageType.Unused29);
|
|
||||||
|
|
||||||
if (tp >= NetMessageType.LibraryError)
|
if (tp >= NetMessageType.LibraryError)
|
||||||
{
|
{
|
||||||
if (sender != null)
|
if (sender != null)
|
||||||
sender.ReceivedLibraryMessage(tp, ptr, payloadByteLength);
|
sender.ReceivedLibraryMessage(tp, ptr, payloadByteLength);
|
||||||
else
|
else
|
||||||
ReceivedUnconnectedLibraryMessage(dnow, ipsender, tp, ptr, payloadByteLength);
|
ReceivedUnconnectedLibraryMessage(now, ipsender, tp, ptr, payloadByteLength);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -473,12 +527,13 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
NetIncomingMessage msg = CreateIncomingMessage(NetIncomingMessageType.Data, payloadByteLength);
|
NetIncomingMessage msg = CreateIncomingMessage(NetIncomingMessageType.Data, payloadByteLength);
|
||||||
msg.m_isFragment = isFragment;
|
msg.m_isFragment = isFragment;
|
||||||
msg.m_receiveTime = dnow;
|
msg.m_receiveTime = now;
|
||||||
msg.m_sequenceNumber = sequenceNumber;
|
msg.m_sequenceNumber = sequenceNumber;
|
||||||
msg.m_receivedMessageType = tp;
|
msg.m_receivedMessageType = tp;
|
||||||
msg.m_senderConnection = sender;
|
msg.m_senderConnection = sender;
|
||||||
msg.m_senderEndPoint = ipsender;
|
msg.m_senderEndPoint = ipsender;
|
||||||
msg.m_bitLength = payloadBitLength;
|
msg.m_bitLength = payloadBitLength;
|
||||||
|
|
||||||
Buffer.BlockCopy(m_receiveBuffer, ptr, msg.m_data, 0, payloadByteLength);
|
Buffer.BlockCopy(m_receiveBuffer, ptr, msg.m_data, 0, payloadByteLength);
|
||||||
if (sender != null)
|
if (sender != null)
|
||||||
{
|
{
|
||||||
@@ -510,9 +565,9 @@ namespace Lidgren.Network
|
|||||||
ptr += payloadByteLength;
|
ptr += payloadByteLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_statistics.PacketReceived(bytesReceived, numMessages);
|
m_statistics.PacketReceived(bytesReceived, numMessages, numFragments);
|
||||||
if (sender != null)
|
if (sender != null)
|
||||||
sender.m_statistics.PacketReceived(bytesReceived, numMessages);
|
sender.m_statistics.PacketReceived(bytesReceived, numMessages, numFragments);
|
||||||
|
|
||||||
} while (m_socket.Available > 0);
|
} while (m_socket.Available > 0);
|
||||||
}
|
}
|
||||||
@@ -525,7 +580,7 @@ namespace Lidgren.Network
|
|||||||
m_executeFlushSendQueue = true;
|
m_executeFlushSendQueue = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void HandleIncomingDiscoveryRequest(double now, IPEndPoint senderEndPoint, int ptr, int payloadByteLength)
|
internal void HandleIncomingDiscoveryRequest(double now, NetEndPoint senderEndPoint, int ptr, int payloadByteLength)
|
||||||
{
|
{
|
||||||
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.DiscoveryRequest))
|
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.DiscoveryRequest))
|
||||||
{
|
{
|
||||||
@@ -539,7 +594,7 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void HandleIncomingDiscoveryResponse(double now, IPEndPoint senderEndPoint, int ptr, int payloadByteLength)
|
internal void HandleIncomingDiscoveryResponse(double now, NetEndPoint senderEndPoint, int ptr, int payloadByteLength)
|
||||||
{
|
{
|
||||||
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.DiscoveryResponse))
|
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.DiscoveryResponse))
|
||||||
{
|
{
|
||||||
@@ -553,7 +608,7 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReceivedUnconnectedLibraryMessage(double now, IPEndPoint senderEndPoint, NetMessageType tp, int ptr, int payloadByteLength)
|
private void ReceivedUnconnectedLibraryMessage(double now, NetEndPoint senderEndPoint, NetMessageType tp, int ptr, int payloadByteLength)
|
||||||
{
|
{
|
||||||
NetConnection shake;
|
NetConnection shake;
|
||||||
if (m_handshakes.TryGetValue(senderEndPoint, out shake))
|
if (m_handshakes.TryGetValue(senderEndPoint, out shake))
|
||||||
@@ -574,10 +629,12 @@ namespace Lidgren.Network
|
|||||||
HandleIncomingDiscoveryResponse(now, senderEndPoint, ptr, payloadByteLength);
|
HandleIncomingDiscoveryResponse(now, senderEndPoint, ptr, payloadByteLength);
|
||||||
return;
|
return;
|
||||||
case NetMessageType.NatIntroduction:
|
case NetMessageType.NatIntroduction:
|
||||||
HandleNatIntroduction(ptr);
|
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.NatIntroductionSuccess))
|
||||||
|
HandleNatIntroduction(ptr);
|
||||||
return;
|
return;
|
||||||
case NetMessageType.NatPunchMessage:
|
case NetMessageType.NatPunchMessage:
|
||||||
HandleNatPunch(ptr, senderEndPoint);
|
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.NatIntroductionSuccess))
|
||||||
|
HandleNatPunch(ptr, senderEndPoint);
|
||||||
return;
|
return;
|
||||||
case NetMessageType.ConnectResponse:
|
case NetMessageType.ConnectResponse:
|
||||||
|
|
||||||
@@ -688,4 +745,4 @@ namespace Lidgren.Network
|
|||||||
return m_readHelperMessage;
|
return m_readHelperMessage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ using System.Net;
|
|||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
#if !__NOIPENDPOINT__
|
||||||
|
using NetEndPoint = System.Net.IPEndPoint;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
public partial class NetPeer
|
public partial class NetPeer
|
||||||
@@ -37,10 +41,10 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
public byte[] Data;
|
public byte[] Data;
|
||||||
public double DelayedUntil;
|
public double DelayedUntil;
|
||||||
public IPEndPoint Target;
|
public NetEndPoint Target;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void SendPacket(int numBytes, IPEndPoint target, int numMessages, out bool connectionReset)
|
internal void SendPacket(int numBytes, NetEndPoint target, int numMessages, out bool connectionReset)
|
||||||
{
|
{
|
||||||
connectionReset = false;
|
connectionReset = false;
|
||||||
|
|
||||||
@@ -48,7 +52,7 @@ namespace Lidgren.Network
|
|||||||
float loss = m_configuration.m_loss;
|
float loss = m_configuration.m_loss;
|
||||||
if (loss > 0.0f)
|
if (loss > 0.0f)
|
||||||
{
|
{
|
||||||
if ((float)NetRandom.Instance.NextDouble() < loss)
|
if ((float)MWCRandom.Instance.NextDouble() < loss)
|
||||||
{
|
{
|
||||||
LogVerbose("Sending packet " + numBytes + " bytes - SIMULATED LOST!");
|
LogVerbose("Sending packet " + numBytes + " bytes - SIMULATED LOST!");
|
||||||
return; // packet "lost"
|
return; // packet "lost"
|
||||||
@@ -66,17 +70,21 @@ namespace Lidgren.Network
|
|||||||
// LogVerbose("Sending packet " + numBytes + " bytes");
|
// LogVerbose("Sending packet " + numBytes + " bytes");
|
||||||
bool wasSent = ActuallySendPacket(m_sendBuffer, numBytes, target, out connectionReset);
|
bool wasSent = ActuallySendPacket(m_sendBuffer, numBytes, target, out connectionReset);
|
||||||
// TODO: handle wasSent == false?
|
// TODO: handle wasSent == false?
|
||||||
|
|
||||||
|
if (m_configuration.m_duplicates > 0.0f && MWCRandom.Instance.NextDouble() < m_configuration.m_duplicates)
|
||||||
|
ActuallySendPacket(m_sendBuffer, numBytes, target, out connectionReset); // send it again!
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int num = 1;
|
int num = 1;
|
||||||
if (m_configuration.m_duplicates > 0.0f && NetRandom.Instance.NextSingle() < m_configuration.m_duplicates)
|
if (m_configuration.m_duplicates > 0.0f && MWCRandom.Instance.NextSingle() < m_configuration.m_duplicates)
|
||||||
num++;
|
num++;
|
||||||
|
|
||||||
float delay = 0;
|
float delay = 0;
|
||||||
for (int i = 0; i < num; i++)
|
for (int i = 0; i < num; i++)
|
||||||
{
|
{
|
||||||
delay = m_configuration.m_minimumOneWayLatency + (NetRandom.Instance.NextSingle() * m_configuration.m_randomOneWayLatency);
|
delay = m_configuration.m_minimumOneWayLatency + (MWCRandom.Instance.NextSingle() * m_configuration.m_randomOneWayLatency);
|
||||||
|
|
||||||
// Enqueue delayed packet
|
// Enqueue delayed packet
|
||||||
DelayedPacket p = new DelayedPacket();
|
DelayedPacket p = new DelayedPacket();
|
||||||
@@ -124,13 +132,16 @@ namespace Lidgren.Network
|
|||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool ActuallySendPacket(byte[] data, int numBytes, IPEndPoint target, out bool connectionReset)
|
internal bool ActuallySendPacket(byte[] data, int numBytes, NetEndPoint target, out bool connectionReset)
|
||||||
{
|
{
|
||||||
connectionReset = false;
|
connectionReset = false;
|
||||||
|
IPAddress ba = default(IPAddress);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
ba = NetUtility.GetCachedBroadcastAddress();
|
||||||
|
|
||||||
// TODO: refactor this check outta here
|
// TODO: refactor this check outta here
|
||||||
if (target.Address == IPAddress.Broadcast)
|
if (target.Address == ba)
|
||||||
{
|
{
|
||||||
// Some networks do not allow
|
// Some networks do not allow
|
||||||
// a global broadcast so we use the BroadcastAddress from the configuration
|
// a global broadcast so we use the BroadcastAddress from the configuration
|
||||||
@@ -167,13 +178,13 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (target.Address == IPAddress.Broadcast)
|
if (target.Address == ba)
|
||||||
m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, false);
|
m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, false);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool SendMTUPacket(int numBytes, IPEndPoint target)
|
internal bool SendMTUPacket(int numBytes, NetEndPoint target)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -209,7 +220,7 @@ namespace Lidgren.Network
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
internal bool SendMTUPacket(int numBytes, IPEndPoint target)
|
internal bool SendMTUPacket(int numBytes, NetEndPoint target)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -246,16 +257,18 @@ namespace Lidgren.Network
|
|||||||
//
|
//
|
||||||
// Release - just send the packet straight away
|
// Release - just send the packet straight away
|
||||||
//
|
//
|
||||||
internal void SendPacket(int numBytes, IPEndPoint target, int numMessages, out bool connectionReset)
|
internal void SendPacket(int numBytes, NetEndPoint target, int numMessages, out bool connectionReset)
|
||||||
{
|
{
|
||||||
#if USE_RELEASE_STATISTICS
|
#if USE_RELEASE_STATISTICS
|
||||||
m_statistics.PacketSent(numBytes, numMessages);
|
m_statistics.PacketSent(numBytes, numMessages);
|
||||||
#endif
|
#endif
|
||||||
connectionReset = false;
|
connectionReset = false;
|
||||||
|
IPAddress ba = default(IPAddress);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// TODO: refactor this check outta here
|
// TODO: refactor this check outta here
|
||||||
if (target.Address == IPAddress.Broadcast)
|
ba = NetUtility.GetCachedBroadcastAddress();
|
||||||
|
if (target.Address == ba)
|
||||||
m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
|
m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
|
||||||
|
|
||||||
int bytesSent = m_socket.SendTo(m_sendBuffer, 0, numBytes, SocketFlags.None, target);
|
int bytesSent = m_socket.SendTo(m_sendBuffer, 0, numBytes, SocketFlags.None, target);
|
||||||
@@ -284,7 +297,7 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (target.Address == IPAddress.Broadcast)
|
if (target.Address == ba)
|
||||||
m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, false);
|
m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, false);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -293,12 +306,6 @@ namespace Lidgren.Network
|
|||||||
private void FlushDelayedPackets()
|
private void FlushDelayedPackets()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SendCallBack(IAsyncResult res)
|
|
||||||
{
|
|
||||||
NetException.Assert(res.IsCompleted == true);
|
|
||||||
m_socket.EndSendTo(res);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -28,8 +28,6 @@ namespace Lidgren.Network
|
|||||||
#if __ANDROID__
|
#if __ANDROID__
|
||||||
Android.Util.Log.WriteLine(Android.Util.LogPriority.Verbose, "", message);
|
Android.Util.Log.WriteLine(Android.Util.LogPriority.Verbose, "", message);
|
||||||
#endif
|
#endif
|
||||||
Debug.WriteLine(message);
|
|
||||||
|
|
||||||
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.VerboseDebugMessage))
|
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.VerboseDebugMessage))
|
||||||
ReleaseMessage(CreateIncomingMessage(NetIncomingMessageType.VerboseDebugMessage, message));
|
ReleaseMessage(CreateIncomingMessage(NetIncomingMessageType.VerboseDebugMessage, message));
|
||||||
}
|
}
|
||||||
@@ -40,8 +38,6 @@ namespace Lidgren.Network
|
|||||||
#if __ANDROID__
|
#if __ANDROID__
|
||||||
Android.Util.Log.WriteLine(Android.Util.LogPriority.Debug, "", message);
|
Android.Util.Log.WriteLine(Android.Util.LogPriority.Debug, "", message);
|
||||||
#endif
|
#endif
|
||||||
Debug.WriteLine(message);
|
|
||||||
|
|
||||||
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.DebugMessage))
|
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.DebugMessage))
|
||||||
ReleaseMessage(CreateIncomingMessage(NetIncomingMessageType.DebugMessage, message));
|
ReleaseMessage(CreateIncomingMessage(NetIncomingMessageType.DebugMessage, message));
|
||||||
}
|
}
|
||||||
@@ -51,8 +47,6 @@ namespace Lidgren.Network
|
|||||||
#if __ANDROID__
|
#if __ANDROID__
|
||||||
Android.Util.Log.WriteLine(Android.Util.LogPriority.Warn, "", message);
|
Android.Util.Log.WriteLine(Android.Util.LogPriority.Warn, "", message);
|
||||||
#endif
|
#endif
|
||||||
Debug.WriteLine(message);
|
|
||||||
|
|
||||||
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.WarningMessage))
|
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.WarningMessage))
|
||||||
ReleaseMessage(CreateIncomingMessage(NetIncomingMessageType.WarningMessage, message));
|
ReleaseMessage(CreateIncomingMessage(NetIncomingMessageType.WarningMessage, message));
|
||||||
}
|
}
|
||||||
@@ -62,8 +56,6 @@ namespace Lidgren.Network
|
|||||||
#if __ANDROID__
|
#if __ANDROID__
|
||||||
Android.Util.Log.WriteLine(Android.Util.LogPriority.Error, "", message);
|
Android.Util.Log.WriteLine(Android.Util.LogPriority.Error, "", message);
|
||||||
#endif
|
#endif
|
||||||
Debug.WriteLine(message);
|
|
||||||
|
|
||||||
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.ErrorMessage))
|
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.ErrorMessage))
|
||||||
ReleaseMessage(CreateIncomingMessage(NetIncomingMessageType.ErrorMessage, message));
|
ReleaseMessage(CreateIncomingMessage(NetIncomingMessageType.ErrorMessage, message));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,14 +6,18 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
public partial class NetPeer
|
public partial class NetPeer
|
||||||
{
|
{
|
||||||
private List<byte[]> m_storagePool; // sorted smallest to largest
|
internal List<byte[]> m_storagePool;
|
||||||
private NetQueue<NetOutgoingMessage> m_outgoingMessagesPool;
|
private NetQueue<NetOutgoingMessage> m_outgoingMessagesPool;
|
||||||
private NetQueue<NetIncomingMessage> m_incomingMessagesPool;
|
private NetQueue<NetIncomingMessage> m_incomingMessagesPool;
|
||||||
|
|
||||||
internal int m_storagePoolBytes;
|
internal int m_storagePoolBytes;
|
||||||
|
internal int m_storageSlotsUsedCount;
|
||||||
|
private int m_maxCacheCount;
|
||||||
|
|
||||||
private void InitializePools()
|
private void InitializePools()
|
||||||
{
|
{
|
||||||
|
m_storageSlotsUsedCount = 0;
|
||||||
|
|
||||||
if (m_configuration.UseMessageRecycling)
|
if (m_configuration.UseMessageRecycling)
|
||||||
{
|
{
|
||||||
m_storagePool = new List<byte[]>(16);
|
m_storagePool = new List<byte[]>(16);
|
||||||
@@ -26,6 +30,8 @@ namespace Lidgren.Network
|
|||||||
m_outgoingMessagesPool = null;
|
m_outgoingMessagesPool = null;
|
||||||
m_incomingMessagesPool = null;
|
m_incomingMessagesPool = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_maxCacheCount = m_configuration.RecycledCacheMaxCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal byte[] GetStorage(int minimumCapacityInBytes)
|
internal byte[] GetStorage(int minimumCapacityInBytes)
|
||||||
@@ -41,6 +47,7 @@ namespace Lidgren.Network
|
|||||||
if (retval != null && retval.Length >= minimumCapacityInBytes)
|
if (retval != null && retval.Length >= minimumCapacityInBytes)
|
||||||
{
|
{
|
||||||
m_storagePool[i] = null;
|
m_storagePool[i] = null;
|
||||||
|
m_storageSlotsUsedCount--;
|
||||||
m_storagePoolBytes -= retval.Length;
|
m_storagePoolBytes -= retval.Length;
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@@ -52,22 +59,39 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
internal void Recycle(byte[] storage)
|
internal void Recycle(byte[] storage)
|
||||||
{
|
{
|
||||||
if (m_storagePool == null)
|
if (m_storagePool == null || storage == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lock (m_storagePool)
|
lock (m_storagePool)
|
||||||
{
|
{
|
||||||
m_storagePoolBytes += storage.Length;
|
|
||||||
int cnt = m_storagePool.Count;
|
int cnt = m_storagePool.Count;
|
||||||
for (int i = 0; i < cnt; i++)
|
for (int i = 0; i < cnt; i++)
|
||||||
{
|
{
|
||||||
if (m_storagePool[i] == null)
|
if (m_storagePool[i] == null)
|
||||||
{
|
{
|
||||||
|
m_storageSlotsUsedCount++;
|
||||||
|
m_storagePoolBytes += storage.Length;
|
||||||
m_storagePool[i] = storage;
|
m_storagePool[i] = storage;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_storagePool.Add(storage);
|
|
||||||
|
if (m_storagePool.Count >= m_maxCacheCount)
|
||||||
|
{
|
||||||
|
// pool is full; replace randomly chosen entry to keep size distribution
|
||||||
|
var idx = NetRandom.Instance.Next(m_storagePool.Count);
|
||||||
|
|
||||||
|
m_storagePoolBytes -= m_storagePool[idx].Length;
|
||||||
|
m_storagePoolBytes += storage.Length;
|
||||||
|
|
||||||
|
m_storagePool[idx] = storage; // replace
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_storageSlotsUsedCount++;
|
||||||
|
m_storagePoolBytes += storage.Length;
|
||||||
|
m_storagePool.Add(storage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,10 +108,8 @@ namespace Lidgren.Network
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public NetOutgoingMessage CreateMessage(string content)
|
public NetOutgoingMessage CreateMessage(string content)
|
||||||
{
|
{
|
||||||
byte[] bytes = Encoding.UTF8.GetBytes(content);
|
var om = CreateMessage(2 + content.Length); // fair guess
|
||||||
NetOutgoingMessage om = CreateMessage(2 + bytes.Length);
|
om.Write(content);
|
||||||
om.WriteVariableUInt32((uint)bytes.Length);
|
|
||||||
om.Write(bytes);
|
|
||||||
return om;
|
return om;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,8 +123,10 @@ namespace Lidgren.Network
|
|||||||
if (m_outgoingMessagesPool == null || !m_outgoingMessagesPool.TryDequeue(out retval))
|
if (m_outgoingMessagesPool == null || !m_outgoingMessagesPool.TryDequeue(out retval))
|
||||||
retval = new NetOutgoingMessage();
|
retval = new NetOutgoingMessage();
|
||||||
|
|
||||||
byte[] storage = GetStorage(initialCapacity);
|
NetException.Assert(retval.m_recyclingCount == 0, "Wrong recycling count! Should be zero" + retval.m_recyclingCount);
|
||||||
retval.m_data = storage;
|
|
||||||
|
if (initialCapacity > 0)
|
||||||
|
retval.m_data = GetStorage(initialCapacity);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@@ -134,17 +158,18 @@ namespace Lidgren.Network
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Recycle(NetIncomingMessage msg)
|
public void Recycle(NetIncomingMessage msg)
|
||||||
{
|
{
|
||||||
if (m_incomingMessagesPool == null)
|
if (m_incomingMessagesPool == null || msg == null)
|
||||||
return;
|
return;
|
||||||
#if DEBUG
|
|
||||||
if (m_incomingMessagesPool.Contains(msg))
|
NetException.Assert(m_incomingMessagesPool.Contains(msg) == false, "Recyling already recycled incoming message! Thread race?");
|
||||||
throw new NetException("Recyling already recycled message! Thread race?");
|
|
||||||
#endif
|
|
||||||
byte[] storage = msg.m_data;
|
byte[] storage = msg.m_data;
|
||||||
msg.m_data = null;
|
msg.m_data = null;
|
||||||
Recycle(storage);
|
Recycle(storage);
|
||||||
msg.Reset();
|
msg.Reset();
|
||||||
m_incomingMessagesPool.Enqueue(msg);
|
|
||||||
|
if (m_incomingMessagesPool.Count < m_maxCacheCount)
|
||||||
|
m_incomingMessagesPool.Enqueue(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -154,34 +179,8 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
if (m_incomingMessagesPool == null)
|
if (m_incomingMessagesPool == null)
|
||||||
return;
|
return;
|
||||||
|
foreach (var im in toRecycle)
|
||||||
// first recycle the storage of each message
|
Recycle(im);
|
||||||
if (m_storagePool != null)
|
|
||||||
{
|
|
||||||
lock (m_storagePool)
|
|
||||||
{
|
|
||||||
foreach (var msg in toRecycle)
|
|
||||||
{
|
|
||||||
var storage = msg.m_data;
|
|
||||||
msg.m_data = null;
|
|
||||||
m_storagePoolBytes += storage.Length;
|
|
||||||
int cnt = m_storagePool.Count;
|
|
||||||
for (int i = 0; i < cnt; i++)
|
|
||||||
{
|
|
||||||
if (m_storagePool[i] == null)
|
|
||||||
{
|
|
||||||
m_storagePool[i] = storage;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
msg.Reset();
|
|
||||||
m_storagePool.Add(storage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// then recycle the message objects
|
|
||||||
m_incomingMessagesPool.Enqueue(toRecycle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Recycle(NetOutgoingMessage msg)
|
internal void Recycle(NetOutgoingMessage msg)
|
||||||
@@ -189,20 +188,25 @@ namespace Lidgren.Network
|
|||||||
if (m_outgoingMessagesPool == null)
|
if (m_outgoingMessagesPool == null)
|
||||||
return;
|
return;
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (m_outgoingMessagesPool.Contains(msg))
|
NetException.Assert(m_outgoingMessagesPool.Contains(msg) == false, "Recyling already recycled outgoing message! Thread race?");
|
||||||
throw new NetException("Recyling already recycled message! Thread race?");
|
if (msg.m_recyclingCount != 0)
|
||||||
|
LogWarning("Wrong recycling count! should be zero; found " + msg.m_recyclingCount);
|
||||||
#endif
|
#endif
|
||||||
|
// setting m_recyclingCount to zero SHOULD be an unnecessary maneuver, if it's not zero something is wrong
|
||||||
|
// however, in RELEASE, we'll just have to accept this and move on with life
|
||||||
|
msg.m_recyclingCount = 0;
|
||||||
|
|
||||||
byte[] storage = msg.m_data;
|
byte[] storage = msg.m_data;
|
||||||
msg.m_data = null;
|
msg.m_data = null;
|
||||||
|
|
||||||
// message fragments cannot be recycled
|
// message fragments cannot be recycled
|
||||||
// TODO: find a way to recycle large message after all fragments has been acknowledged; or? possibly better just to garbage collect them
|
// TODO: find a way to recycle large message after all fragments has been acknowledged; or? possibly better just to garbage collect them
|
||||||
if (msg.m_fragmentGroup == 0)
|
if (msg.m_fragmentGroup == 0)
|
||||||
Recycle(storage);
|
Recycle(storage);
|
||||||
|
|
||||||
msg.Reset();
|
msg.Reset();
|
||||||
m_outgoingMessagesPool.Enqueue(msg);
|
if (m_outgoingMessagesPool.Count < m_maxCacheCount)
|
||||||
|
m_outgoingMessagesPool.Enqueue(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ using System.Collections.Generic;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
|
#if !__NOIPENDPOINT__
|
||||||
|
using NetEndPoint = System.Net.IPEndPoint;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
public partial class NetPeer
|
public partial class NetPeer
|
||||||
@@ -46,8 +50,10 @@ namespace Lidgren.Network
|
|||||||
throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");
|
throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");
|
||||||
msg.m_isSent = true;
|
msg.m_isSent = true;
|
||||||
|
|
||||||
|
bool suppressFragmentation = (method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.UnreliableSequenced) && m_configuration.UnreliableSizeBehaviour != NetUnreliableSizeBehaviour.NormalFragmentation;
|
||||||
|
|
||||||
int len = NetConstants.UnfragmentedMessageHeaderSize + msg.LengthBytes; // headers + length, faster than calling msg.GetEncodedSize
|
int len = NetConstants.UnfragmentedMessageHeaderSize + msg.LengthBytes; // headers + length, faster than calling msg.GetEncodedSize
|
||||||
if (len <= recipient.m_currentMTU)
|
if (len <= recipient.m_currentMTU || suppressFragmentation)
|
||||||
{
|
{
|
||||||
Interlocked.Increment(ref msg.m_recyclingCount);
|
Interlocked.Increment(ref msg.m_recyclingCount);
|
||||||
return recipient.EnqueueMessage(msg, method, sequenceChannel);
|
return recipient.EnqueueMessage(msg, method, sequenceChannel);
|
||||||
@@ -57,17 +63,25 @@ namespace Lidgren.Network
|
|||||||
// message must be fragmented!
|
// message must be fragmented!
|
||||||
if (recipient.m_status != NetConnectionStatus.Connected)
|
if (recipient.m_status != NetConnectionStatus.Connected)
|
||||||
return NetSendResult.FailedNotConnected;
|
return NetSendResult.FailedNotConnected;
|
||||||
SendFragmentedMessage(msg, new NetConnection[] { recipient }, method, sequenceChannel);
|
return SendFragmentedMessage(msg, new NetConnection[] { recipient }, method, sequenceChannel);
|
||||||
return NetSendResult.Queued; // could be different for each connection; Queued is "most true"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static int GetMTU(IList<NetConnection> recipients)
|
internal static int GetMTU(IList<NetConnection> recipients)
|
||||||
{
|
{
|
||||||
int count = recipients.Count;
|
int count = recipients.Count;
|
||||||
NetException.Assert(count > 0);
|
|
||||||
|
|
||||||
int mtu = int.MaxValue;
|
int mtu = int.MaxValue;
|
||||||
|
if (count < 1)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
throw new NetException("GetMTU called with no recipients");
|
||||||
|
#else
|
||||||
|
// we don't have access to the particular peer, so just use default MTU
|
||||||
|
return NetPeerConfiguration.kDefaultMTU;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
for(int i=0;i<count;i++)
|
for(int i=0;i<count;i++)
|
||||||
{
|
{
|
||||||
var conn = recipients[i];
|
var conn = recipients[i];
|
||||||
@@ -85,23 +99,30 @@ namespace Lidgren.Network
|
|||||||
/// <param name="recipients">The list of recipients to send to</param>
|
/// <param name="recipients">The list of recipients to send to</param>
|
||||||
/// <param name="method">How to deliver the message</param>
|
/// <param name="method">How to deliver the message</param>
|
||||||
/// <param name="sequenceChannel">Sequence channel within the delivery method</param>
|
/// <param name="sequenceChannel">Sequence channel within the delivery method</param>
|
||||||
public void SendMessage(NetOutgoingMessage msg, List<NetConnection> recipients, NetDeliveryMethod method, int sequenceChannel)
|
public void SendMessage(NetOutgoingMessage msg, IList<NetConnection> recipients, NetDeliveryMethod method, int sequenceChannel)
|
||||||
{
|
{
|
||||||
if (msg == null)
|
if (msg == null)
|
||||||
throw new ArgumentNullException("msg");
|
throw new ArgumentNullException("msg");
|
||||||
if (recipients == null)
|
if (recipients == null)
|
||||||
|
{
|
||||||
|
if (msg.m_isSent == false)
|
||||||
|
Recycle(msg);
|
||||||
throw new ArgumentNullException("recipients");
|
throw new ArgumentNullException("recipients");
|
||||||
|
}
|
||||||
if (recipients.Count < 1)
|
if (recipients.Count < 1)
|
||||||
|
{
|
||||||
|
if (msg.m_isSent == false)
|
||||||
|
Recycle(msg);
|
||||||
throw new NetException("recipients must contain at least one item");
|
throw new NetException("recipients must contain at least one item");
|
||||||
|
}
|
||||||
if (method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.ReliableUnordered)
|
if (method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.ReliableUnordered)
|
||||||
NetException.Assert(sequenceChannel == 0, "Delivery method " + method + " cannot use sequence channels other than 0!");
|
NetException.Assert(sequenceChannel == 0, "Delivery method " + method + " cannot use sequence channels other than 0!");
|
||||||
if (msg.m_isSent)
|
if (msg.m_isSent)
|
||||||
throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");
|
throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");
|
||||||
|
msg.m_isSent = true;
|
||||||
|
|
||||||
int mtu = GetMTU(recipients);
|
int mtu = GetMTU(recipients);
|
||||||
|
|
||||||
msg.m_isSent = true;
|
|
||||||
|
|
||||||
int len = msg.GetEncodedSize();
|
int len = msg.GetEncodedSize();
|
||||||
if (len <= mtu)
|
if (len <= mtu)
|
||||||
{
|
{
|
||||||
@@ -114,7 +135,7 @@ namespace Lidgren.Network
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
NetSendResult res = conn.EnqueueMessage(msg, method, sequenceChannel);
|
NetSendResult res = conn.EnqueueMessage(msg, method, sequenceChannel);
|
||||||
if (res != NetSendResult.Queued && res != NetSendResult.Sent)
|
if (res == NetSendResult.Dropped)
|
||||||
Interlocked.Decrement(ref msg.m_recyclingCount);
|
Interlocked.Decrement(ref msg.m_recyclingCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,21 +162,21 @@ namespace Lidgren.Network
|
|||||||
if (msg.LengthBytes > m_configuration.MaximumTransmissionUnit)
|
if (msg.LengthBytes > m_configuration.MaximumTransmissionUnit)
|
||||||
throw new NetException("Unconnected messages too long! Must be shorter than NetConfiguration.MaximumTransmissionUnit (currently " + m_configuration.MaximumTransmissionUnit + ")");
|
throw new NetException("Unconnected messages too long! Must be shorter than NetConfiguration.MaximumTransmissionUnit (currently " + m_configuration.MaximumTransmissionUnit + ")");
|
||||||
|
|
||||||
IPAddress adr = NetUtility.Resolve(host);
|
msg.m_isSent = true;
|
||||||
|
msg.m_messageType = NetMessageType.Unconnected;
|
||||||
|
|
||||||
|
var adr = NetUtility.Resolve(host);
|
||||||
if (adr == null)
|
if (adr == null)
|
||||||
throw new NetException("Failed to resolve " + host);
|
throw new NetException("Failed to resolve " + host);
|
||||||
|
|
||||||
msg.m_messageType = NetMessageType.Unconnected;
|
|
||||||
msg.m_isSent = true;
|
|
||||||
|
|
||||||
Interlocked.Increment(ref msg.m_recyclingCount);
|
Interlocked.Increment(ref msg.m_recyclingCount);
|
||||||
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(new IPEndPoint(adr, port), msg));
|
m_unsentUnconnectedMessages.Enqueue(new NetTuple<NetEndPoint, NetOutgoingMessage>(new NetEndPoint(adr, port), msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Send a message to an unconnected host
|
/// Send a message to an unconnected host
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SendUnconnectedMessage(NetOutgoingMessage msg, IPEndPoint recipient)
|
public void SendUnconnectedMessage(NetOutgoingMessage msg, NetEndPoint recipient)
|
||||||
{
|
{
|
||||||
if (msg == null)
|
if (msg == null)
|
||||||
throw new ArgumentNullException("msg");
|
throw new ArgumentNullException("msg");
|
||||||
@@ -170,13 +191,13 @@ namespace Lidgren.Network
|
|||||||
msg.m_isSent = true;
|
msg.m_isSent = true;
|
||||||
|
|
||||||
Interlocked.Increment(ref msg.m_recyclingCount);
|
Interlocked.Increment(ref msg.m_recyclingCount);
|
||||||
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(recipient, msg));
|
m_unsentUnconnectedMessages.Enqueue(new NetTuple<NetEndPoint, NetOutgoingMessage>(recipient, msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Send a message to an unconnected host
|
/// Send a message to an unconnected host
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SendUnconnectedMessage(NetOutgoingMessage msg, IList<IPEndPoint> recipients)
|
public void SendUnconnectedMessage(NetOutgoingMessage msg, IList<NetEndPoint> recipients)
|
||||||
{
|
{
|
||||||
if (msg == null)
|
if (msg == null)
|
||||||
throw new ArgumentNullException("msg");
|
throw new ArgumentNullException("msg");
|
||||||
@@ -193,35 +214,42 @@ namespace Lidgren.Network
|
|||||||
msg.m_isSent = true;
|
msg.m_isSent = true;
|
||||||
|
|
||||||
Interlocked.Add(ref msg.m_recyclingCount, recipients.Count);
|
Interlocked.Add(ref msg.m_recyclingCount, recipients.Count);
|
||||||
foreach(IPEndPoint ep in recipients)
|
foreach (NetEndPoint ep in recipients)
|
||||||
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(ep, msg));
|
m_unsentUnconnectedMessages.Enqueue(new NetTuple<NetEndPoint, NetOutgoingMessage>(ep, msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Send a message to this exact same netpeer (loopback)
|
/// Send a message to this exact same netpeer (loopback)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SendUnconnectedToSelf(NetOutgoingMessage msg)
|
public void SendUnconnectedToSelf(NetOutgoingMessage om)
|
||||||
{
|
{
|
||||||
if (msg == null)
|
if (om == null)
|
||||||
throw new ArgumentNullException("msg");
|
throw new ArgumentNullException("msg");
|
||||||
if (msg.m_isSent)
|
if (om.m_isSent)
|
||||||
throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");
|
throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");
|
||||||
|
|
||||||
msg.m_messageType = NetMessageType.Unconnected;
|
om.m_messageType = NetMessageType.Unconnected;
|
||||||
msg.m_isSent = true;
|
om.m_isSent = true;
|
||||||
|
|
||||||
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.UnconnectedData) == false)
|
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.UnconnectedData) == false)
|
||||||
|
{
|
||||||
|
Interlocked.Decrement(ref om.m_recyclingCount);
|
||||||
return; // dropping unconnected message since it's not enabled for receiving
|
return; // dropping unconnected message since it's not enabled for receiving
|
||||||
|
}
|
||||||
|
|
||||||
NetIncomingMessage om = CreateIncomingMessage(NetIncomingMessageType.UnconnectedData, msg.LengthBytes);
|
// convert outgoing to incoming
|
||||||
om.Write(msg);
|
NetIncomingMessage im = CreateIncomingMessage(NetIncomingMessageType.UnconnectedData, om.LengthBytes);
|
||||||
om.m_isFragment = false;
|
im.Write(om);
|
||||||
om.m_receiveTime = NetTime.Now;
|
im.m_isFragment = false;
|
||||||
om.m_senderConnection = null;
|
im.m_receiveTime = NetTime.Now;
|
||||||
om.m_senderEndPoint = m_socket.LocalEndPoint as IPEndPoint;
|
im.m_senderConnection = null;
|
||||||
NetException.Assert(om.m_bitLength == msg.LengthBits);
|
im.m_senderEndPoint = m_socket.LocalEndPoint as NetEndPoint;
|
||||||
|
NetException.Assert(im.m_bitLength == om.LengthBits);
|
||||||
|
|
||||||
ReleaseMessage(om);
|
// recycle outgoing message
|
||||||
|
Recycle(om);
|
||||||
|
|
||||||
|
ReleaseMessage(im);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+71
-30
@@ -3,6 +3,10 @@ using System.Threading;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
|
#if !__NOIPENDPOINT__
|
||||||
|
using NetEndPoint = System.Net.IPEndPoint;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -14,9 +18,10 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
private int m_listenPort;
|
private int m_listenPort;
|
||||||
private object m_tag;
|
private object m_tag;
|
||||||
|
private object m_messageReceivedEventCreationLock = new object();
|
||||||
|
|
||||||
internal readonly List<NetConnection> m_connections;
|
internal readonly List<NetConnection> m_connections;
|
||||||
private readonly Dictionary<IPEndPoint, NetConnection> m_connectionLookup;
|
private readonly Dictionary<NetEndPoint, NetConnection> m_connectionLookup;
|
||||||
|
|
||||||
private string m_shutdownReason;
|
private string m_shutdownReason;
|
||||||
|
|
||||||
@@ -36,7 +41,13 @@ namespace Lidgren.Network
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (m_messageReceivedEvent == null)
|
if (m_messageReceivedEvent == null)
|
||||||
m_messageReceivedEvent = new AutoResetEvent(false);
|
{
|
||||||
|
lock (m_messageReceivedEventCreationLock) // make sure we don't create more than one event object
|
||||||
|
{
|
||||||
|
if (m_messageReceivedEvent == null)
|
||||||
|
m_messageReceivedEvent = new AutoResetEvent(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
return m_messageReceivedEvent;
|
return m_messageReceivedEvent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,11 +117,11 @@ namespace Lidgren.Network
|
|||||||
m_configuration = config;
|
m_configuration = config;
|
||||||
m_statistics = new NetPeerStatistics(this);
|
m_statistics = new NetPeerStatistics(this);
|
||||||
m_releasedIncomingMessages = new NetQueue<NetIncomingMessage>(4);
|
m_releasedIncomingMessages = new NetQueue<NetIncomingMessage>(4);
|
||||||
m_unsentUnconnectedMessages = new NetQueue<NetTuple<IPEndPoint, NetOutgoingMessage>>(2);
|
m_unsentUnconnectedMessages = new NetQueue<NetTuple<NetEndPoint, NetOutgoingMessage>>(2);
|
||||||
m_connections = new List<NetConnection>();
|
m_connections = new List<NetConnection>();
|
||||||
m_connectionLookup = new Dictionary<IPEndPoint, NetConnection>();
|
m_connectionLookup = new Dictionary<NetEndPoint, NetConnection>();
|
||||||
m_handshakes = new Dictionary<IPEndPoint, NetConnection>();
|
m_handshakes = new Dictionary<NetEndPoint, NetConnection>();
|
||||||
m_senderRemote = (EndPoint)new IPEndPoint(IPAddress.Any, 0);
|
m_senderRemote = (EndPoint)new NetEndPoint(IPAddress.Any, 0);
|
||||||
m_status = NetPeerStatus.NotRunning;
|
m_status = NetPeerStatus.NotRunning;
|
||||||
m_receivedFragmentGroups = new Dictionary<NetConnection, Dictionary<int, ReceivedFragmentGroup>>();
|
m_receivedFragmentGroups = new Dictionary<NetConnection, Dictionary<int, ReceivedFragmentGroup>>();
|
||||||
}
|
}
|
||||||
@@ -149,13 +160,13 @@ namespace Lidgren.Network
|
|||||||
m_upnp.Discover(this);
|
m_upnp.Discover(this);
|
||||||
|
|
||||||
// allow some time for network thread to start up in case they call Connect() or UPnP calls immediately
|
// allow some time for network thread to start up in case they call Connect() or UPnP calls immediately
|
||||||
Thread.Sleep(50);
|
NetUtility.Sleep(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the connection, if any, for a certain remote endpoint
|
/// Get the connection, if any, for a certain remote endpoint
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NetConnection GetConnection(IPEndPoint ep)
|
public NetConnection GetConnection(NetEndPoint ep)
|
||||||
{
|
{
|
||||||
NetConnection retval;
|
NetConnection retval;
|
||||||
|
|
||||||
@@ -169,15 +180,24 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Read a pending message from any connection, blocking up to maxMillis if needed
|
/// Read a pending message from any connection, blocking up to maxMillis if needed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NetIncomingMessage WaitMessage(int maxMillis)
|
public NetIncomingMessage WaitMessage(int maxMillis)
|
||||||
{
|
{
|
||||||
var msg = ReadMessage();
|
NetIncomingMessage msg = ReadMessage();
|
||||||
if (msg != null)
|
|
||||||
return msg; // no need to wait; we already have a message to deliver
|
while (msg == null)
|
||||||
if (m_messageReceivedEvent != null)
|
{
|
||||||
m_messageReceivedEvent.WaitOne(maxMillis);
|
// This could return true...
|
||||||
return ReadMessage();
|
if (!MessageReceivedEvent.WaitOne(maxMillis))
|
||||||
}
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... while this will still returns null. That's why we need to cycle.
|
||||||
|
msg = ReadMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Read a pending message from any connection, if any
|
/// Read a pending message from any connection, if any
|
||||||
@@ -218,8 +238,8 @@ namespace Lidgren.Network
|
|||||||
return added;
|
return added;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send message immediately
|
// send message immediately and recycle it
|
||||||
internal void SendLibrary(NetOutgoingMessage msg, IPEndPoint recipient)
|
internal void SendLibrary(NetOutgoingMessage msg, NetEndPoint recipient)
|
||||||
{
|
{
|
||||||
VerifyNetworkThread();
|
VerifyNetworkThread();
|
||||||
NetException.Assert(msg.m_isSent == false);
|
NetException.Assert(msg.m_isSent == false);
|
||||||
@@ -227,6 +247,18 @@ namespace Lidgren.Network
|
|||||||
bool connReset;
|
bool connReset;
|
||||||
int len = msg.Encode(m_sendBuffer, 0, 0);
|
int len = msg.Encode(m_sendBuffer, 0, 0);
|
||||||
SendPacket(len, recipient, 1, out connReset);
|
SendPacket(len, recipient, 1, out connReset);
|
||||||
|
|
||||||
|
// no reliability, no multiple recipients - we can just recycle this message immediately
|
||||||
|
msg.m_recyclingCount = 0;
|
||||||
|
Recycle(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NetEndPoint GetNetEndPoint(string host, int port)
|
||||||
|
{
|
||||||
|
IPAddress address = NetUtility.Resolve(host);
|
||||||
|
if (address == null)
|
||||||
|
throw new NetException("Could not resolve host");
|
||||||
|
return new NetEndPoint(address, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -234,7 +266,7 @@ namespace Lidgren.Network
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public NetConnection Connect(string host, int port)
|
public NetConnection Connect(string host, int port)
|
||||||
{
|
{
|
||||||
return Connect(new IPEndPoint(NetUtility.Resolve(host), port), null);
|
return Connect(GetNetEndPoint(host, port), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -242,13 +274,13 @@ namespace Lidgren.Network
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public NetConnection Connect(string host, int port, NetOutgoingMessage hailMessage)
|
public NetConnection Connect(string host, int port, NetOutgoingMessage hailMessage)
|
||||||
{
|
{
|
||||||
return Connect(new IPEndPoint(NetUtility.Resolve(host), port), hailMessage);
|
return Connect(GetNetEndPoint(host, port), hailMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a connection to a remote endpoint
|
/// Create a connection to a remote endpoint
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NetConnection Connect(IPEndPoint remoteEndPoint)
|
public NetConnection Connect(NetEndPoint remoteEndPoint)
|
||||||
{
|
{
|
||||||
return Connect(remoteEndPoint, null);
|
return Connect(remoteEndPoint, null);
|
||||||
}
|
}
|
||||||
@@ -256,7 +288,7 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a connection to a remote endpoint
|
/// Create a connection to a remote endpoint
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual NetConnection Connect(IPEndPoint remoteEndPoint, NetOutgoingMessage hailMessage)
|
public virtual NetConnection Connect(NetEndPoint remoteEndPoint, NetOutgoingMessage hailMessage)
|
||||||
{
|
{
|
||||||
if (remoteEndPoint == null)
|
if (remoteEndPoint == null)
|
||||||
throw new ArgumentNullException("remoteEndPoint");
|
throw new ArgumentNullException("remoteEndPoint");
|
||||||
@@ -281,7 +313,7 @@ namespace Lidgren.Network
|
|||||||
break;
|
break;
|
||||||
case NetConnectionStatus.RespondedConnect:
|
case NetConnectionStatus.RespondedConnect:
|
||||||
// send another response
|
// send another response
|
||||||
hs.SendConnectResponse((float)NetTime.Now, false);
|
hs.SendConnectResponse(NetTime.Now, false);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// weird
|
// weird
|
||||||
@@ -308,18 +340,27 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Send raw bytes; only used for debugging
|
/// Send raw bytes; only used for debugging
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#if DEBUG
|
public void RawSend(byte[] arr, int offset, int length, NetEndPoint destination)
|
||||||
public void RawSend(byte[] arr, int offset, int length, IPEndPoint destination)
|
{
|
||||||
#else
|
|
||||||
internal void RawSend(byte[] arr, int offset, int length, IPEndPoint destination)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
// wrong thread - this miiiight crash with network thread... but what's a boy to do.
|
// wrong thread - this miiiight crash with network thread... but what's a boy to do.
|
||||||
Array.Copy(arr, offset, m_sendBuffer, 0, length);
|
Array.Copy(arr, offset, m_sendBuffer, 0, length);
|
||||||
bool unused;
|
bool unused;
|
||||||
SendPacket(length, destination, 1, out unused);
|
SendPacket(length, destination, 1, out unused);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// In DEBUG, throws an exception, in RELEASE logs an error message
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
internal void ThrowOrLog(string message)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
throw new NetException(message);
|
||||||
|
#else
|
||||||
|
LogError(message);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disconnects all active connections and closes the socket
|
/// Disconnects all active connections and closes the socket
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -27,6 +27,20 @@ namespace Lidgren.Network
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class NetPeerConfiguration
|
public sealed class NetPeerConfiguration
|
||||||
{
|
{
|
||||||
|
// Maximum transmission unit
|
||||||
|
// Ethernet can take 1500 bytes of payload, so lets stay below that.
|
||||||
|
// The aim is for a max full packet to be 1440 bytes (30 x 48 bytes, lower than 1468)
|
||||||
|
// -20 bytes IP header
|
||||||
|
// -8 bytes UDP header
|
||||||
|
// -4 bytes to be on the safe side and align to 8-byte boundary
|
||||||
|
// Total 1408 bytes
|
||||||
|
// Note that lidgren headers (5 bytes) are not included here; since it's part of the "mtu payload"
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default MTU value in bytes
|
||||||
|
/// </summary>
|
||||||
|
public const int kDefaultMTU = 1408;
|
||||||
|
|
||||||
private const string c_isLockedMessage = "You may not modify the NetPeerConfiguration after it has been used to initialize a NetPeer";
|
private const string c_isLockedMessage = "You may not modify the NetPeerConfiguration after it has been used to initialize a NetPeer";
|
||||||
|
|
||||||
private bool m_isLocked;
|
private bool m_isLocked;
|
||||||
@@ -39,9 +53,12 @@ namespace Lidgren.Network
|
|||||||
internal int m_defaultOutgoingMessageCapacity;
|
internal int m_defaultOutgoingMessageCapacity;
|
||||||
internal float m_pingInterval;
|
internal float m_pingInterval;
|
||||||
internal bool m_useMessageRecycling;
|
internal bool m_useMessageRecycling;
|
||||||
|
internal int m_recycledCacheMaxCount;
|
||||||
internal float m_connectionTimeout;
|
internal float m_connectionTimeout;
|
||||||
internal bool m_enableUPnP;
|
internal bool m_enableUPnP;
|
||||||
internal bool m_autoFlushSendQueue;
|
internal bool m_autoFlushSendQueue;
|
||||||
|
private NetUnreliableSizeBehaviour m_unreliableSizeBehaviour;
|
||||||
|
internal bool m_suppressUnreliableUnorderedAcks;
|
||||||
|
|
||||||
internal NetIncomingMessageType m_disabledTypes;
|
internal NetIncomingMessageType m_disabledTypes;
|
||||||
internal int m_port;
|
internal int m_port;
|
||||||
@@ -69,12 +86,12 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(appIdentifier))
|
if (string.IsNullOrEmpty(appIdentifier))
|
||||||
throw new NetException("App identifier must be at least one character long");
|
throw new NetException("App identifier must be at least one character long");
|
||||||
m_appIdentifier = appIdentifier.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
m_appIdentifier = appIdentifier;
|
||||||
|
|
||||||
//
|
//
|
||||||
// default values
|
// default values
|
||||||
//
|
//
|
||||||
m_disabledTypes = NetIncomingMessageType.ConnectionApproval | NetIncomingMessageType.UnconnectedData | NetIncomingMessageType.VerboseDebugMessage | NetIncomingMessageType.ConnectionLatencyUpdated;
|
m_disabledTypes = NetIncomingMessageType.ConnectionApproval | NetIncomingMessageType.UnconnectedData | NetIncomingMessageType.VerboseDebugMessage | NetIncomingMessageType.ConnectionLatencyUpdated | NetIncomingMessageType.NatIntroductionSuccess;
|
||||||
m_networkThreadName = "Lidgren network thread";
|
m_networkThreadName = "Lidgren network thread";
|
||||||
m_localAddress = IPAddress.Any;
|
m_localAddress = IPAddress.Any;
|
||||||
m_broadcastAddress = IPAddress.Broadcast;
|
m_broadcastAddress = IPAddress.Broadcast;
|
||||||
@@ -92,22 +109,17 @@ namespace Lidgren.Network
|
|||||||
m_pingInterval = 4.0f;
|
m_pingInterval = 4.0f;
|
||||||
m_connectionTimeout = 25.0f;
|
m_connectionTimeout = 25.0f;
|
||||||
m_useMessageRecycling = true;
|
m_useMessageRecycling = true;
|
||||||
|
m_recycledCacheMaxCount = 64;
|
||||||
m_resendHandshakeInterval = 3.0f;
|
m_resendHandshakeInterval = 3.0f;
|
||||||
m_maximumHandshakeAttempts = 5;
|
m_maximumHandshakeAttempts = 5;
|
||||||
m_autoFlushSendQueue = true;
|
m_autoFlushSendQueue = true;
|
||||||
|
m_suppressUnreliableUnorderedAcks = false;
|
||||||
|
|
||||||
// Maximum transmission unit
|
m_maximumTransmissionUnit = kDefaultMTU;
|
||||||
// Ethernet can take 1500 bytes of payload, so lets stay below that.
|
|
||||||
// The aim is for a max full packet to be 1440 bytes (30 x 48 bytes, lower than 1468)
|
|
||||||
// -20 bytes IP header
|
|
||||||
// -8 bytes UDP header
|
|
||||||
// -4 bytes to be on the safe side and align to 8-byte boundary
|
|
||||||
// Total 1408 bytes
|
|
||||||
// Note that lidgren headers (5 bytes) are not included here; since it's part of the "mtu payload"
|
|
||||||
m_maximumTransmissionUnit = 1408;
|
|
||||||
m_autoExpandMTU = false;
|
m_autoExpandMTU = false;
|
||||||
m_expandMTUFrequency = 2.0f;
|
m_expandMTUFrequency = 2.0f;
|
||||||
m_expandMTUFailAttempts = 5;
|
m_expandMTUFailAttempts = 5;
|
||||||
|
m_unreliableSizeBehaviour = NetUnreliableSizeBehaviour.IgnoreMTU;
|
||||||
|
|
||||||
m_loss = 0.0f;
|
m_loss = 0.0f;
|
||||||
m_minimumOneWayLatency = 0.0f;
|
m_minimumOneWayLatency = 0.0f;
|
||||||
@@ -165,6 +177,15 @@ namespace Lidgren.Network
|
|||||||
return !((m_disabledTypes & type) == type);
|
return !((m_disabledTypes & type) == type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the behaviour of unreliable sends above MTU
|
||||||
|
/// </summary>
|
||||||
|
public NetUnreliableSizeBehaviour UnreliableSizeBehaviour
|
||||||
|
{
|
||||||
|
get { return m_unreliableSizeBehaviour; }
|
||||||
|
set { m_unreliableSizeBehaviour = value; }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the name of the library network thread. Cannot be changed once NetPeer is initialized.
|
/// Gets or sets the name of the library network thread. Cannot be changed once NetPeer is initialized.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -241,6 +262,20 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the maximum number of incoming/outgoing messages to keep in the recycle cache.
|
||||||
|
/// </summary>
|
||||||
|
public int RecycledCacheMaxCount
|
||||||
|
{
|
||||||
|
get { return m_recycledCacheMaxCount; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (m_isLocked)
|
||||||
|
throw new NetException(c_isLockedMessage);
|
||||||
|
m_recycledCacheMaxCount = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the number of seconds timeout will be postponed on a successful ping/pong
|
/// Gets or sets the number of seconds timeout will be postponed on a successful ping/pong
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -278,6 +313,20 @@ namespace Lidgren.Network
|
|||||||
set { m_autoFlushSendQueue = value; }
|
set { m_autoFlushSendQueue = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If true, will not send acks for unreliable unordered messages. This will save bandwidth, but disable flow control and duplicate detection for this type of messages.
|
||||||
|
/// </summary>
|
||||||
|
public bool SuppressUnreliableUnorderedAcks
|
||||||
|
{
|
||||||
|
get { return m_suppressUnreliableUnorderedAcks; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (m_isLocked)
|
||||||
|
throw new NetException(c_isLockedMessage);
|
||||||
|
m_suppressUnreliableUnorderedAcks = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the local ip address to bind to. Defaults to IPAddress.Any. Cannot be changed once NetPeer is initialized.
|
/// Gets or sets the local ip address to bind to. Defaults to IPAddress.Any. Cannot be changed once NetPeer is initialized.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -468,4 +517,25 @@ namespace Lidgren.Network
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Behaviour of unreliable sends above MTU
|
||||||
|
/// </summary>
|
||||||
|
public enum NetUnreliableSizeBehaviour
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Sending an unreliable message will ignore MTU and send everything in a single packet; this is the new default
|
||||||
|
/// </summary>
|
||||||
|
IgnoreMTU = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Old behaviour; use normal fragmentation for unreliable messages - if a fragment is dropped, memory for received fragments are never reclaimed!
|
||||||
|
/// </summary>
|
||||||
|
NormalFragmentation = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Alternate behaviour; just drops unreliable messages above MTU
|
||||||
|
/// </summary>
|
||||||
|
DropAboveMTU = 2,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
internal int m_sentMessages;
|
internal int m_sentMessages;
|
||||||
internal int m_receivedMessages;
|
internal int m_receivedMessages;
|
||||||
|
internal int m_receivedFragments;
|
||||||
|
|
||||||
internal int m_sentBytes;
|
internal int m_sentBytes;
|
||||||
internal int m_receivedBytes;
|
internal int m_receivedBytes;
|
||||||
@@ -58,6 +59,7 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
m_sentMessages = 0;
|
m_sentMessages = 0;
|
||||||
m_receivedMessages = 0;
|
m_receivedMessages = 0;
|
||||||
|
m_receivedFragments = 0;
|
||||||
|
|
||||||
m_sentBytes = 0;
|
m_sentBytes = 0;
|
||||||
m_receivedBytes = 0;
|
m_receivedBytes = 0;
|
||||||
@@ -103,41 +105,35 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the number of bytes in the recycled pool
|
/// Gets the number of bytes in the recycled pool
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int BytesInRecyclePool { get { return m_peer.m_storagePoolBytes; } }
|
public int BytesInRecyclePool
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (m_peer.m_storagePool)
|
||||||
|
return m_peer.m_storagePoolBytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if USE_RELEASE_STATISTICS
|
#if !USE_RELEASE_STATISTICS
|
||||||
|
[Conditional("DEBUG")]
|
||||||
|
#endif
|
||||||
internal void PacketSent(int numBytes, int numMessages)
|
internal void PacketSent(int numBytes, int numMessages)
|
||||||
{
|
{
|
||||||
m_sentPackets++;
|
m_sentPackets++;
|
||||||
m_sentBytes += numBytes;
|
m_sentBytes += numBytes;
|
||||||
m_sentMessages += numMessages;
|
m_sentMessages += numMessages;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
[Conditional("DEBUG")]
|
|
||||||
internal void PacketSent(int numBytes, int numMessages)
|
|
||||||
{
|
|
||||||
m_sentPackets++;
|
|
||||||
m_sentBytes += numBytes;
|
|
||||||
m_sentMessages += numMessages;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if USE_RELEASE_STATISTICS
|
#if !USE_RELEASE_STATISTICS
|
||||||
internal void PacketReceived(int numBytes, int numMessages)
|
|
||||||
{
|
|
||||||
m_receivedPackets++;
|
|
||||||
m_receivedBytes += numBytes;
|
|
||||||
m_receivedMessages += numMessages;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
[Conditional("DEBUG")]
|
[Conditional("DEBUG")]
|
||||||
internal void PacketReceived(int numBytes, int numMessages)
|
#endif
|
||||||
|
internal void PacketReceived(int numBytes, int numMessages, int numFragments)
|
||||||
{
|
{
|
||||||
m_receivedPackets++;
|
m_receivedPackets++;
|
||||||
m_receivedBytes += numBytes;
|
m_receivedBytes += numBytes;
|
||||||
m_receivedMessages += numMessages;
|
m_receivedMessages += numMessages;
|
||||||
|
m_receivedFragments += numFragments;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a string that represents this object
|
/// Returns a string that represents this object
|
||||||
@@ -148,13 +144,14 @@ namespace Lidgren.Network
|
|||||||
bdr.AppendLine(m_peer.ConnectionsCount.ToString() + " connections");
|
bdr.AppendLine(m_peer.ConnectionsCount.ToString() + " connections");
|
||||||
#if DEBUG || USE_RELEASE_STATISTICS
|
#if DEBUG || USE_RELEASE_STATISTICS
|
||||||
bdr.AppendLine("Sent " + m_sentBytes + " bytes in " + m_sentMessages + " messages in " + m_sentPackets + " packets");
|
bdr.AppendLine("Sent " + m_sentBytes + " bytes in " + m_sentMessages + " messages in " + m_sentPackets + " packets");
|
||||||
bdr.AppendLine("Received " + m_receivedBytes + " bytes in " + m_receivedMessages + " messages in " + m_receivedPackets + " packets");
|
bdr.AppendLine("Received " + m_receivedBytes + " bytes in " + m_receivedMessages + " messages (of which " + m_receivedFragments + " fragments) in " + m_receivedPackets + " packets");
|
||||||
#else
|
#else
|
||||||
bdr.AppendLine("Sent (n/a) bytes in (n/a) messages in (n/a) packets");
|
bdr.AppendLine("Sent (n/a) bytes in (n/a) messages in (n/a) packets");
|
||||||
bdr.AppendLine("Received (n/a) bytes in (n/a) messages in (n/a) packets");
|
bdr.AppendLine("Received (n/a) bytes in (n/a) messages in (n/a) packets");
|
||||||
#endif
|
#endif
|
||||||
bdr.AppendLine("Storage allocated " + m_bytesAllocated + " bytes");
|
bdr.AppendLine("Storage allocated " + m_bytesAllocated + " bytes");
|
||||||
bdr.AppendLine("Recycled pool " + m_peer.m_storagePoolBytes + " bytes");
|
if (m_peer.m_storagePool != null)
|
||||||
|
bdr.AppendLine("Recycled pool " + m_peer.m_storagePoolBytes + " bytes (" + m_peer.m_storageSlotsUsedCount + " entries)");
|
||||||
return bdr.ToString();
|
return bdr.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ using System.Diagnostics;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Comment for Linux Mono users: reports of library thread hangs on EnterReadLock() suggests switching to plain lock() works better
|
||||||
|
//
|
||||||
|
|
||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -52,12 +56,29 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the number of items in the queue
|
/// Gets the number of items in the queue
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Count { get { return m_size; } }
|
public int Count {
|
||||||
|
get
|
||||||
|
{
|
||||||
|
m_lock.EnterReadLock();
|
||||||
|
int count = m_size;
|
||||||
|
m_lock.ExitReadLock();
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the current capacity for the queue
|
/// Gets the current capacity for the queue
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Capacity { get { return m_items.Length; } }
|
public int Capacity
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
m_lock.EnterReadLock();
|
||||||
|
int capacity = m_items.Length;
|
||||||
|
m_lock.ExitReadLock();
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// NetQueue constructor
|
/// NetQueue constructor
|
||||||
@@ -193,6 +214,15 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
throw;
|
||||||
|
#else
|
||||||
|
item = default(T);
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
m_lock.ExitWriteLock();
|
m_lock.ExitWriteLock();
|
||||||
@@ -200,7 +230,7 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets an item from the head of the queue, or returns default(T) if empty
|
/// Gets all items from the head of the queue, or returns number of items popped
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int TryDrain(IList<T> addTo)
|
public int TryDrain(IList<T> addTo)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,281 @@
|
|||||||
|
using System;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace Lidgren.Network
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Multiply With Carry random
|
||||||
|
/// </summary>
|
||||||
|
public class MWCRandom : NetRandom
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get global instance of MWCRandom
|
||||||
|
/// </summary>
|
||||||
|
public static new readonly MWCRandom Instance = new MWCRandom();
|
||||||
|
|
||||||
|
private uint m_w, m_z;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor with randomized seed
|
||||||
|
/// </summary>
|
||||||
|
public MWCRandom()
|
||||||
|
{
|
||||||
|
Initialize(NetRandomSeed.GetUInt64());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// (Re)initialize this instance with provided 32 bit seed
|
||||||
|
/// </summary>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public override void Initialize(uint seed)
|
||||||
|
{
|
||||||
|
m_w = seed;
|
||||||
|
m_z = seed * 16777619;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// (Re)initialize this instance with provided 64 bit seed
|
||||||
|
/// </summary>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void Initialize(ulong seed)
|
||||||
|
{
|
||||||
|
m_w = (uint)seed;
|
||||||
|
m_z = (uint)(seed >> 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a random value from UInt32.MinValue to UInt32.MaxValue, inclusively
|
||||||
|
/// </summary>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public override uint NextUInt32()
|
||||||
|
{
|
||||||
|
m_z = 36969 * (m_z & 65535) + (m_z >> 16);
|
||||||
|
m_w = 18000 * (m_w & 65535) + (m_w >> 16);
|
||||||
|
return ((m_z << 16) + m_w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Xor Shift based random
|
||||||
|
/// </summary>
|
||||||
|
public sealed class XorShiftRandom : NetRandom
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get global instance of XorShiftRandom
|
||||||
|
/// </summary>
|
||||||
|
public static new readonly XorShiftRandom Instance = new XorShiftRandom();
|
||||||
|
|
||||||
|
private const uint c_x = 123456789;
|
||||||
|
private const uint c_y = 362436069;
|
||||||
|
private const uint c_z = 521288629;
|
||||||
|
private const uint c_w = 88675123;
|
||||||
|
|
||||||
|
private uint m_x, m_y, m_z, m_w;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor with randomized seed
|
||||||
|
/// </summary>
|
||||||
|
public XorShiftRandom()
|
||||||
|
{
|
||||||
|
Initialize(NetRandomSeed.GetUInt64());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor with provided 64 bit seed
|
||||||
|
/// </summary>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public XorShiftRandom(ulong seed)
|
||||||
|
{
|
||||||
|
Initialize(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// (Re)initialize this instance with provided 32 bit seed
|
||||||
|
/// </summary>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public override void Initialize(uint seed)
|
||||||
|
{
|
||||||
|
m_x = (uint)seed;
|
||||||
|
m_y = c_y;
|
||||||
|
m_z = c_z;
|
||||||
|
m_w = c_w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// (Re)initialize this instance with provided 64 bit seed
|
||||||
|
/// </summary>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void Initialize(ulong seed)
|
||||||
|
{
|
||||||
|
m_x = (uint)seed;
|
||||||
|
m_y = c_y;
|
||||||
|
m_z = (uint)(seed << 32);
|
||||||
|
m_w = c_w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a random value from UInt32.MinValue to UInt32.MaxValue, inclusively
|
||||||
|
/// </summary>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public override uint NextUInt32()
|
||||||
|
{
|
||||||
|
uint t = (m_x ^ (m_x << 11));
|
||||||
|
m_x = m_y; m_y = m_z; m_z = m_w;
|
||||||
|
return (m_w = (m_w ^ (m_w >> 19)) ^ (t ^ (t >> 8)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mersenne Twister based random
|
||||||
|
/// </summary>
|
||||||
|
public sealed class MersenneTwisterRandom : NetRandom
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get global instance of MersenneTwisterRandom
|
||||||
|
/// </summary>
|
||||||
|
public static new readonly MersenneTwisterRandom Instance = new MersenneTwisterRandom();
|
||||||
|
|
||||||
|
private const int N = 624;
|
||||||
|
private const int M = 397;
|
||||||
|
private const uint MATRIX_A = 0x9908b0dfU;
|
||||||
|
private const uint UPPER_MASK = 0x80000000U;
|
||||||
|
private const uint LOWER_MASK = 0x7fffffffU;
|
||||||
|
private const uint TEMPER1 = 0x9d2c5680U;
|
||||||
|
private const uint TEMPER2 = 0xefc60000U;
|
||||||
|
private const int TEMPER3 = 11;
|
||||||
|
private const int TEMPER4 = 7;
|
||||||
|
private const int TEMPER5 = 15;
|
||||||
|
private const int TEMPER6 = 18;
|
||||||
|
|
||||||
|
private UInt32[] mt;
|
||||||
|
private int mti;
|
||||||
|
private UInt32[] mag01;
|
||||||
|
|
||||||
|
private const double c_realUnitInt = 1.0 / ((double)int.MaxValue + 1.0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor with randomized seed
|
||||||
|
/// </summary>
|
||||||
|
public MersenneTwisterRandom()
|
||||||
|
{
|
||||||
|
Initialize(NetRandomSeed.GetUInt32());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor with provided 32 bit seed
|
||||||
|
/// </summary>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public MersenneTwisterRandom(uint seed)
|
||||||
|
{
|
||||||
|
Initialize(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// (Re)initialize this instance with provided 32 bit seed
|
||||||
|
/// </summary>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public override void Initialize(uint seed)
|
||||||
|
{
|
||||||
|
mt = new UInt32[N];
|
||||||
|
mti = N + 1;
|
||||||
|
mag01 = new UInt32[] { 0x0U, MATRIX_A };
|
||||||
|
mt[0] = seed;
|
||||||
|
for (int i = 1; i < N; i++)
|
||||||
|
mt[i] = (UInt32)(1812433253 * (mt[i - 1] ^ (mt[i - 1] >> 30)) + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a random value from UInt32.MinValue to UInt32.MaxValue, inclusively
|
||||||
|
/// </summary>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public override uint NextUInt32()
|
||||||
|
{
|
||||||
|
UInt32 y;
|
||||||
|
if (mti >= N)
|
||||||
|
{
|
||||||
|
GenRandAll();
|
||||||
|
mti = 0;
|
||||||
|
}
|
||||||
|
y = mt[mti++];
|
||||||
|
y ^= (y >> TEMPER3);
|
||||||
|
y ^= (y << TEMPER4) & TEMPER1;
|
||||||
|
y ^= (y << TEMPER5) & TEMPER2;
|
||||||
|
y ^= (y >> TEMPER6);
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenRandAll()
|
||||||
|
{
|
||||||
|
int kk = 1;
|
||||||
|
UInt32 y;
|
||||||
|
UInt32 p;
|
||||||
|
y = mt[0] & UPPER_MASK;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
p = mt[kk];
|
||||||
|
mt[kk - 1] = mt[kk + (M - 1)] ^ ((y | (p & LOWER_MASK)) >> 1) ^ mag01[p & 1];
|
||||||
|
y = p & UPPER_MASK;
|
||||||
|
} while (++kk < N - M + 1);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
p = mt[kk];
|
||||||
|
mt[kk - 1] = mt[kk + (M - N - 1)] ^ ((y | (p & LOWER_MASK)) >> 1) ^ mag01[p & 1];
|
||||||
|
y = p & UPPER_MASK;
|
||||||
|
} while (++kk < N);
|
||||||
|
p = mt[0];
|
||||||
|
mt[N - 1] = mt[M - 1] ^ ((y | (p & LOWER_MASK)) >> 1) ^ mag01[p & 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// RNGCryptoServiceProvider based random; very slow but cryptographically safe
|
||||||
|
/// </summary>
|
||||||
|
public class CryptoRandom : NetRandom
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Global instance of CryptoRandom
|
||||||
|
/// </summary>
|
||||||
|
public static new readonly CryptoRandom Instance = new CryptoRandom();
|
||||||
|
|
||||||
|
private RandomNumberGenerator m_rnd = new RNGCryptoServiceProvider();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Seed in CryptoRandom does not create deterministic sequences
|
||||||
|
/// </summary>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public override void Initialize(uint seed)
|
||||||
|
{
|
||||||
|
byte[] tmp = new byte[seed % 16];
|
||||||
|
m_rnd.GetBytes(tmp); // just prime it
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a random value from UInt32.MinValue to UInt32.MaxValue, inclusively
|
||||||
|
/// </summary>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public override uint NextUInt32()
|
||||||
|
{
|
||||||
|
var bytes = new byte[4];
|
||||||
|
m_rnd.GetBytes(bytes);
|
||||||
|
return (uint)bytes[0] | (((uint)bytes[1]) << 8) | (((uint)bytes[2]) << 16) | (((uint)bytes[3]) << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fill the specified buffer with random values
|
||||||
|
/// </summary>
|
||||||
|
public override void NextBytes(byte[] buffer)
|
||||||
|
{
|
||||||
|
m_rnd.GetBytes(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fills all bytes from offset to offset + length in buffer with random values
|
||||||
|
/// </summary>
|
||||||
|
public override void NextBytes(byte[] buffer, int offset, int length)
|
||||||
|
{
|
||||||
|
var bytes = new byte[length];
|
||||||
|
m_rnd.GetBytes(bytes);
|
||||||
|
Array.Copy(bytes, 0, buffer, offset, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+95
-291
@@ -1,373 +1,177 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A fast random number generator for .NET
|
/// NetRandom base class
|
||||||
/// Colin Green, January 2005
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// September 4th 2005
|
public abstract class NetRandom : Random
|
||||||
/// Added NextBytesUnsafe() - commented out by default.
|
|
||||||
/// Fixed bug in Reinitialise() - y,z and w variables were not being reset.
|
|
||||||
///
|
|
||||||
/// Key points:
|
|
||||||
/// 1) Based on a simple and fast xor-shift pseudo random number generator (RNG) specified in:
|
|
||||||
/// Marsaglia, George. (2003). Xorshift RNGs.
|
|
||||||
/// http://www.jstatsoft.org/v08/i14/xorshift.pdf
|
|
||||||
///
|
|
||||||
/// This particular implementation of xorshift has a period of 2^128-1. See the above paper to see
|
|
||||||
/// how this can be easily extened if you need a longer period. At the time of writing I could find no
|
|
||||||
/// information on the period of System.Random for comparison.
|
|
||||||
///
|
|
||||||
/// 2) Faster than System.Random. Up to 8x faster, depending on which methods are called.
|
|
||||||
///
|
|
||||||
/// 3) Direct replacement for System.Random. This class implements all of the methods that System.Random
|
|
||||||
/// does plus some additional methods. The like named methods are functionally equivalent.
|
|
||||||
///
|
|
||||||
/// 4) Allows fast re-initialisation with a seed, unlike System.Random which accepts a seed at construction
|
|
||||||
/// time which then executes a relatively expensive initialisation routine. This provides a vast speed improvement
|
|
||||||
/// if you need to reset the pseudo-random number sequence many times, e.g. if you want to re-generate the same
|
|
||||||
/// sequence many times. An alternative might be to cache random numbers in an array, but that approach is limited
|
|
||||||
/// by memory capacity and the fact that you may also want a large number of different sequences cached. Each sequence
|
|
||||||
/// can each be represented by a single seed value (int) when using FastRandom.
|
|
||||||
///
|
|
||||||
/// Notes.
|
|
||||||
/// A further performance improvement can be obtained by declaring local variables as static, thus avoiding
|
|
||||||
/// re-allocation of variables on each call. However care should be taken if multiple instances of
|
|
||||||
/// FastRandom are in use or if being used in a multi-threaded environment.
|
|
||||||
public class NetRandom
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a global NetRandom instance
|
/// Get global instance of NetRandom (uses MWCRandom)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly NetRandom Instance = new NetRandom();
|
public static NetRandom Instance = new MWCRandom();
|
||||||
|
|
||||||
// The +1 ensures NextDouble doesn't generate 1.0
|
private const double c_realUnitInt = 1.0 / ((double)int.MaxValue + 1.0);
|
||||||
const double REAL_UNIT_INT = 1.0 / ((double)int.MaxValue + 1.0);
|
|
||||||
const double REAL_UNIT_UINT = 1.0 / ((double)uint.MaxValue + 1.0);
|
|
||||||
const uint Y = 842502087, Z = 3579807591, W = 273326509;
|
|
||||||
|
|
||||||
private static int s_extraSeed = 42;
|
|
||||||
|
|
||||||
uint x, y, z, w;
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialises a new instance using time dependent seed.
|
/// Constructor with randomized seed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NetRandom()
|
public NetRandom()
|
||||||
{
|
{
|
||||||
// Initialise using the system tick count.
|
Initialize(NetRandomSeed.GetUInt32());
|
||||||
Reinitialise(GetSeed(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialises a new instance using an int value as seed.
|
/// Constructor with provided 32 bit seed
|
||||||
/// This constructor signature is provided to maintain compatibility with
|
|
||||||
/// System.Random
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NetRandom(int seed)
|
public NetRandom(int seed)
|
||||||
{
|
{
|
||||||
Reinitialise(seed);
|
Initialize((uint)seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a semi-random seed based on an object
|
/// (Re)initialize this instance with provided 32 bit seed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static int GetSeed(object forObject)
|
[CLSCompliant(false)]
|
||||||
|
public virtual void Initialize(uint seed)
|
||||||
{
|
{
|
||||||
// mix some semi-random properties
|
// should be abstract, but non-CLS compliant methods can't be abstract!
|
||||||
int seed = (int)Environment.TickCount;
|
throw new NotImplementedException("Implement this in inherited classes");
|
||||||
seed ^= forObject.GetHashCode();
|
|
||||||
//seed ^= (int)(Stopwatch.GetTimestamp());
|
|
||||||
//seed ^= (int)(Environment.WorkingSet); // will return 0 on mono
|
|
||||||
|
|
||||||
int extraSeed = System.Threading.Interlocked.Increment(ref s_extraSeed);
|
|
||||||
|
|
||||||
return seed + extraSeed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Public Methods [Reinitialisation]
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reinitialises using an int value as a seed.
|
/// Generates a random value from UInt32.MinValue to UInt32.MaxValue, inclusively
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="seed"></param>
|
[CLSCompliant(false)]
|
||||||
public void Reinitialise(int seed)
|
public virtual uint NextUInt32()
|
||||||
{
|
{
|
||||||
// The only stipulation stated for the xorshift RNG is that at least one of
|
// should be abstract, but non-CLS compliant methods can't be abstract!
|
||||||
// the seeds x,y,z,w is non-zero. We fulfill that requirement by only allowing
|
throw new NotImplementedException("Implement this in inherited classes");
|
||||||
// resetting of the x seed
|
|
||||||
x = (uint)seed;
|
|
||||||
y = Y;
|
|
||||||
z = Z;
|
|
||||||
w = W;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Public Methods [System.Random functionally equivalent methods]
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a random int over the range 0 to int.MaxValue-1.
|
/// Generates a random value that is greater or equal than 0 and less than Int32.MaxValue
|
||||||
/// MaxValue is not generated in order to remain functionally equivalent to System.Random.Next().
|
|
||||||
/// This does slightly eat into some of the performance gain over System.Random, but not much.
|
|
||||||
/// For better performance see:
|
|
||||||
///
|
|
||||||
/// Call NextInt() for an int over the range 0 to int.MaxValue.
|
|
||||||
///
|
|
||||||
/// Call NextUInt() and cast the result to an int to generate an int over the full Int32 value range
|
|
||||||
/// including negative values.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
public override int Next()
|
||||||
public int Next()
|
|
||||||
{
|
{
|
||||||
uint t = (x ^ (x << 11));
|
var retval = (int)(0x7FFFFFFF & NextUInt32());
|
||||||
x = y; y = z; z = w;
|
if (retval == 0x7FFFFFFF)
|
||||||
w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
|
return NextInt32();
|
||||||
|
return retval;
|
||||||
// Handle the special case where the value int.MaxValue is generated. This is outside of
|
|
||||||
// the range of permitted values, so we therefore call Next() to try again.
|
|
||||||
uint rtn = w & 0x7FFFFFFF;
|
|
||||||
if (rtn == 0x7FFFFFFF)
|
|
||||||
return Next();
|
|
||||||
return (int)rtn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a random int over the range 0 to upperBound-1, and not including upperBound.
|
/// Generates a random value greater or equal than 0 and less or equal than Int32.MaxValue (inclusively)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="upperBound"></param>
|
public int NextInt32()
|
||||||
/// <returns></returns>
|
|
||||||
public int Next(int upperBound)
|
|
||||||
{
|
{
|
||||||
if (upperBound < 0)
|
return (int)(0x7FFFFFFF & NextUInt32());
|
||||||
throw new ArgumentOutOfRangeException("upperBound", upperBound, "upperBound must be >=0");
|
|
||||||
|
|
||||||
uint t = (x ^ (x << 11));
|
|
||||||
x = y; y = z; z = w;
|
|
||||||
|
|
||||||
// The explicit int cast before the first multiplication gives better performance.
|
|
||||||
// See comments in NextDouble.
|
|
||||||
return (int)((REAL_UNIT_INT * (int)(0x7FFFFFFF & (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8))))) * upperBound);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a random int over the range lowerBound to upperBound-1, and not including upperBound.
|
/// Returns random value larger or equal to 0.0 and less than 1.0
|
||||||
/// upperBound must be >= lowerBound. lowerBound may be negative.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="lowerBound"></param>
|
public override double NextDouble()
|
||||||
/// <param name="upperBound"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public int Next(int lowerBound, int upperBound)
|
|
||||||
{
|
{
|
||||||
if (lowerBound > upperBound)
|
return c_realUnitInt * NextInt32();
|
||||||
throw new ArgumentOutOfRangeException("upperBound", upperBound, "upperBound must be >=lowerBound");
|
|
||||||
|
|
||||||
uint t = (x ^ (x << 11));
|
|
||||||
x = y; y = z; z = w;
|
|
||||||
|
|
||||||
// The explicit int cast before the first multiplication gives better performance.
|
|
||||||
// See comments in NextDouble.
|
|
||||||
int range = upperBound - lowerBound;
|
|
||||||
if (range < 0)
|
|
||||||
{ // If range is <0 then an overflow has occured and must resort to using long integer arithmetic instead (slower).
|
|
||||||
// We also must use all 32 bits of precision, instead of the normal 31, which again is slower.
|
|
||||||
return lowerBound + (int)((REAL_UNIT_UINT * (double)(w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)))) * (double)((long)upperBound - (long)lowerBound));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 31 bits of precision will suffice if range<=int.MaxValue. This allows us to cast to an int and gain
|
|
||||||
// a little more performance.
|
|
||||||
return lowerBound + (int)((REAL_UNIT_INT * (double)(int)(0x7FFFFFFF & (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8))))) * (double)range);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a random double. Values returned are from 0.0 up to but not including 1.0.
|
/// Returns random value is greater or equal than 0.0 and less than 1.0
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
protected override double Sample()
|
||||||
public double NextDouble()
|
|
||||||
{
|
{
|
||||||
uint t = (x ^ (x << 11));
|
return c_realUnitInt * NextInt32();
|
||||||
x = y; y = z; z = w;
|
|
||||||
|
|
||||||
// Here we can gain a 2x speed improvement by generating a value that can be cast to
|
|
||||||
// an int instead of the more easily available uint. If we then explicitly cast to an
|
|
||||||
// int the compiler will then cast the int to a double to perform the multiplication,
|
|
||||||
// this final cast is a lot faster than casting from a uint to a double. The extra cast
|
|
||||||
// to an int is very fast (the allocated bits remain the same) and so the overall effect
|
|
||||||
// of the extra cast is a significant performance improvement.
|
|
||||||
//
|
|
||||||
// Also note that the loss of one bit of precision is equivalent to what occurs within
|
|
||||||
// System.Random.
|
|
||||||
return (REAL_UNIT_INT * (int)(0x7FFFFFFF & (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a random single. Values returned are from 0.0 up to but not including 1.0.
|
/// Returns random value is greater or equal than 0.0f and less than 1.0f
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float NextSingle()
|
public float NextSingle()
|
||||||
{
|
{
|
||||||
return (float)NextDouble();
|
var retval = (float)(c_realUnitInt * NextInt32());
|
||||||
|
if (retval == 1.0f)
|
||||||
|
return NextSingle();
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fills the provided byte array with random bytes.
|
/// Returns a random value is greater or equal than 0 and less than maxValue
|
||||||
/// This method is functionally equivalent to System.Random.NextBytes().
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="buffer"></param>
|
public override int Next(int maxValue)
|
||||||
public void NextBytes(byte[] buffer)
|
|
||||||
{
|
{
|
||||||
// Fill up the bulk of the buffer in chunks of 4 bytes at a time.
|
return (int)(NextDouble() * maxValue);
|
||||||
uint x = this.x, y = this.y, z = this.z, w = this.w;
|
|
||||||
int i = 0;
|
|
||||||
uint t;
|
|
||||||
for (int bound = buffer.Length - 3; i < bound; )
|
|
||||||
{
|
|
||||||
// Generate 4 bytes.
|
|
||||||
// Increased performance is achieved by generating 4 random bytes per loop.
|
|
||||||
// Also note that no mask needs to be applied to zero out the higher order bytes before
|
|
||||||
// casting because the cast ignores thos bytes. Thanks to Stefan Troschütz for pointing this out.
|
|
||||||
t = (x ^ (x << 11));
|
|
||||||
x = y; y = z; z = w;
|
|
||||||
w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
|
|
||||||
|
|
||||||
buffer[i++] = (byte)w;
|
|
||||||
buffer[i++] = (byte)(w >> 8);
|
|
||||||
buffer[i++] = (byte)(w >> 16);
|
|
||||||
buffer[i++] = (byte)(w >> 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill up any remaining bytes in the buffer.
|
|
||||||
if (i < buffer.Length)
|
|
||||||
{
|
|
||||||
// Generate 4 bytes.
|
|
||||||
t = (x ^ (x << 11));
|
|
||||||
x = y; y = z; z = w;
|
|
||||||
w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
|
|
||||||
|
|
||||||
buffer[i++] = (byte)w;
|
|
||||||
if (i < buffer.Length)
|
|
||||||
{
|
|
||||||
buffer[i++] = (byte)(w >> 8);
|
|
||||||
if (i < buffer.Length)
|
|
||||||
{
|
|
||||||
buffer[i++] = (byte)(w >> 16);
|
|
||||||
if (i < buffer.Length)
|
|
||||||
{
|
|
||||||
buffer[i] = (byte)(w >> 24);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.x = x; this.y = y; this.z = z; this.w = w;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// /// <summary>
|
|
||||||
// /// A version of NextBytes that uses a pointer to set 4 bytes of the byte buffer in one operation
|
|
||||||
// /// thus providing a nice speedup. The loop is also partially unrolled to allow out-of-order-execution,
|
|
||||||
// /// this results in about a x2 speedup on an AMD Athlon. Thus performance may vary wildly on different CPUs
|
|
||||||
// /// depending on the number of execution units available.
|
|
||||||
// ///
|
|
||||||
// /// Another significant speedup is obtained by setting the 4 bytes by indexing pDWord (e.g. pDWord[i++]=w)
|
|
||||||
// /// instead of adjusting it dereferencing it (e.g. *pDWord++=w).
|
|
||||||
// ///
|
|
||||||
// /// Note that this routine requires the unsafe compilation flag to be specified and so is commented out by default.
|
|
||||||
// /// </summary>
|
|
||||||
// /// <param name="buffer"></param>
|
|
||||||
// public unsafe void NextBytesUnsafe(byte[] buffer)
|
|
||||||
// {
|
|
||||||
// if(buffer.Length % 8 != 0)
|
|
||||||
// throw new ArgumentException("Buffer length must be divisible by 8", "buffer");
|
|
||||||
//
|
|
||||||
// uint x=this.x, y=this.y, z=this.z, w=this.w;
|
|
||||||
//
|
|
||||||
// fixed(byte* pByte0 = buffer)
|
|
||||||
// {
|
|
||||||
// uint* pDWord = (uint*)pByte0;
|
|
||||||
// for(int i=0, len=buffer.Length>>2; i < len; i+=2)
|
|
||||||
// {
|
|
||||||
// uint t=(x^(x<<11));
|
|
||||||
// x=y; y=z; z=w;
|
|
||||||
// pDWord[i] = w = (w^(w>>19))^(t^(t>>8));
|
|
||||||
//
|
|
||||||
// t=(x^(x<<11));
|
|
||||||
// x=y; y=z; z=w;
|
|
||||||
// pDWord[i+1] = w = (w^(w>>19))^(t^(t>>8));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// this.x=x; this.y=y; this.z=z; this.w=w;
|
|
||||||
// }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Public Methods [Methods not present on System.Random]
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a uint. Values returned are over the full range of a uint,
|
/// Returns a random value is greater or equal than minValue and less than maxValue
|
||||||
/// uint.MinValue to uint.MaxValue, inclusive.
|
/// </summary>
|
||||||
///
|
public override int Next(int minValue, int maxValue)
|
||||||
/// This is the fastest method for generating a single random number because the underlying
|
{
|
||||||
/// random number generator algorithm generates 32 random bits that can be cast directly to
|
return minValue + (int)(NextDouble() * (double)(maxValue - minValue));
|
||||||
/// a uint.
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a random value between UInt64.MinValue to UInt64.MaxValue
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[CLSCompliant(false)]
|
[CLSCompliant(false)]
|
||||||
public uint NextUInt()
|
public ulong NextUInt64()
|
||||||
{
|
{
|
||||||
uint t = (x ^ (x << 11));
|
ulong retval = NextUInt32();
|
||||||
x = y; y = z; z = w;
|
retval |= NextUInt32() << 32;
|
||||||
return (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)));
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private uint m_boolValues;
|
||||||
/// Generates a random int over the range 0 to int.MaxValue, inclusive.
|
private int m_nextBoolIndex;
|
||||||
/// This method differs from Next() only in that the range is 0 to int.MaxValue
|
|
||||||
/// and not 0 to int.MaxValue-1.
|
|
||||||
///
|
|
||||||
/// The slight difference in range means this method is slightly faster than Next()
|
|
||||||
/// but is not functionally equivalent to System.Random.Next().
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public int NextInt()
|
|
||||||
{
|
|
||||||
uint t = (x ^ (x << 11));
|
|
||||||
x = y; y = z; z = w;
|
|
||||||
return (int)(0x7FFFFFFF & (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8))));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Buffer 32 bits in bitBuffer, return 1 at a time, keep track of how many have been returned
|
|
||||||
// with bitBufferIdx.
|
|
||||||
uint bitBuffer;
|
|
||||||
uint bitMask = 1;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a single random bit.
|
/// Returns true or false, randomly
|
||||||
/// This method's performance is improved by generating 32 bits in one operation and storing them
|
|
||||||
/// ready for future calls.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
|
||||||
public bool NextBool()
|
public bool NextBool()
|
||||||
{
|
{
|
||||||
if (bitMask == 1)
|
if (m_nextBoolIndex >= 32)
|
||||||
{
|
{
|
||||||
// Generate 32 more bits.
|
m_boolValues = NextUInt32();
|
||||||
uint t = (x ^ (x << 11));
|
m_nextBoolIndex = 1;
|
||||||
x = y; y = z; z = w;
|
|
||||||
bitBuffer = w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
|
|
||||||
|
|
||||||
// Reset the bitMask that tells us which bit to read next.
|
|
||||||
bitMask = 0x80000000;
|
|
||||||
return (bitBuffer & bitMask) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (bitBuffer & (bitMask >>= 1)) == 0;
|
var retval = ((m_boolValues >> m_nextBoolIndex) & 1) == 1;
|
||||||
|
m_nextBoolIndex++;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fills all bytes from offset to offset + length in buffer with random values
|
||||||
|
/// </summary>
|
||||||
|
public virtual void NextBytes(byte[] buffer, int offset, int length)
|
||||||
|
{
|
||||||
|
int full = length / 4;
|
||||||
|
int ptr = offset;
|
||||||
|
for (int i = 0; i < full; i++)
|
||||||
|
{
|
||||||
|
uint r = NextUInt32();
|
||||||
|
buffer[ptr++] = (byte)r;
|
||||||
|
buffer[ptr++] = (byte)(r >> 8);
|
||||||
|
buffer[ptr++] = (byte)(r >> 16);
|
||||||
|
buffer[ptr++] = (byte)(r >> 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rest = length - (full * 4);
|
||||||
|
for (int i = 0; i < rest; i++)
|
||||||
|
buffer[ptr++] = (byte)NextUInt32();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
/// <summary>
|
||||||
|
/// Fill the specified buffer with random values
|
||||||
|
/// </summary>
|
||||||
|
public override void NextBytes(byte[] buffer)
|
||||||
|
{
|
||||||
|
NextBytes(buffer, 0, buffer.Length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Lidgren.Network
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class for generating random seeds
|
||||||
|
/// </summary>
|
||||||
|
public static class NetRandomSeed
|
||||||
|
{
|
||||||
|
private static int m_seedIncrement = -1640531527;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a 32 bit random seed
|
||||||
|
/// </summary>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static uint GetUInt32()
|
||||||
|
{
|
||||||
|
ulong seed = GetUInt64();
|
||||||
|
uint low = (uint)seed;
|
||||||
|
uint high = (uint)(seed >> 32);
|
||||||
|
return low ^ high;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a 64 bit random seed
|
||||||
|
/// </summary>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static ulong GetUInt64()
|
||||||
|
{
|
||||||
|
var guidBytes = Guid.NewGuid().ToByteArray();
|
||||||
|
ulong seed =
|
||||||
|
((ulong)guidBytes[0] << (8 * 0)) |
|
||||||
|
((ulong)guidBytes[1] << (8 * 1)) |
|
||||||
|
((ulong)guidBytes[2] << (8 * 2)) |
|
||||||
|
((ulong)guidBytes[3] << (8 * 3)) |
|
||||||
|
((ulong)guidBytes[4] << (8 * 4)) |
|
||||||
|
((ulong)guidBytes[5] << (8 * 5)) |
|
||||||
|
((ulong)guidBytes[6] << (8 * 6)) |
|
||||||
|
((ulong)guidBytes[7] << (8 * 7));
|
||||||
|
|
||||||
|
return seed ^ NetUtility.GetPlatformSeed(m_seedIncrement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -66,8 +66,9 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
if (relate < 0)
|
if (relate < 0)
|
||||||
{
|
{
|
||||||
m_peer.LogVerbose("Received message #" + message.m_sequenceNumber + " DROPPING DUPLICATE");
|
|
||||||
// duplicate
|
// duplicate
|
||||||
|
m_connection.m_statistics.MessageDropped();
|
||||||
|
m_peer.LogVerbose("Received message #" + message.m_sequenceNumber + " DROPPING DUPLICATE");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,6 +76,7 @@ namespace Lidgren.Network
|
|||||||
if (relate > m_windowSize)
|
if (relate > m_windowSize)
|
||||||
{
|
{
|
||||||
// too early message!
|
// too early message!
|
||||||
|
m_connection.m_statistics.MessageDropped();
|
||||||
m_peer.LogDebug("Received " + message + " TOO EARLY! Expected " + m_windowStart);
|
m_peer.LogDebug("Received " + message + " TOO EARLY! Expected " + m_windowStart);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,19 +13,27 @@ namespace Lidgren.Network
|
|||||||
private int m_windowSize;
|
private int m_windowSize;
|
||||||
private int m_sendStart;
|
private int m_sendStart;
|
||||||
|
|
||||||
|
private bool m_anyStoredResends;
|
||||||
|
|
||||||
private NetBitVector m_receivedAcks;
|
private NetBitVector m_receivedAcks;
|
||||||
internal NetStoredReliableMessage[] m_storedMessages;
|
internal NetStoredReliableMessage[] m_storedMessages;
|
||||||
|
|
||||||
internal float m_resendDelay;
|
internal double m_resendDelay;
|
||||||
|
|
||||||
internal override int WindowSize { get { return m_windowSize; } }
|
internal override int WindowSize { get { return m_windowSize; } }
|
||||||
|
|
||||||
|
internal override bool NeedToSendMessages()
|
||||||
|
{
|
||||||
|
return base.NeedToSendMessages() || m_anyStoredResends;
|
||||||
|
}
|
||||||
|
|
||||||
internal NetReliableSenderChannel(NetConnection connection, int windowSize)
|
internal NetReliableSenderChannel(NetConnection connection, int windowSize)
|
||||||
{
|
{
|
||||||
m_connection = connection;
|
m_connection = connection;
|
||||||
m_windowSize = windowSize;
|
m_windowSize = windowSize;
|
||||||
m_windowStart = 0;
|
m_windowStart = 0;
|
||||||
m_sendStart = 0;
|
m_sendStart = 0;
|
||||||
|
m_anyStoredResends = false;
|
||||||
m_receivedAcks = new NetBitVector(NetConstants.NumSequenceNumbers);
|
m_receivedAcks = new NetBitVector(NetConstants.NumSequenceNumbers);
|
||||||
m_storedMessages = new NetStoredReliableMessage[m_windowSize];
|
m_storedMessages = new NetStoredReliableMessage[m_windowSize];
|
||||||
m_queuedSends = new NetQueue<NetOutgoingMessage>(8);
|
m_queuedSends = new NetQueue<NetOutgoingMessage>(8);
|
||||||
@@ -44,6 +52,7 @@ namespace Lidgren.Network
|
|||||||
m_receivedAcks.Clear();
|
m_receivedAcks.Clear();
|
||||||
for (int i = 0; i < m_storedMessages.Length; i++)
|
for (int i = 0; i < m_storedMessages.Length; i++)
|
||||||
m_storedMessages[i].Reset();
|
m_storedMessages[i].Reset();
|
||||||
|
m_anyStoredResends = false;
|
||||||
m_queuedSends.Clear();
|
m_queuedSends.Clear();
|
||||||
m_windowStart = 0;
|
m_windowStart = 0;
|
||||||
m_sendStart = 0;
|
m_sendStart = 0;
|
||||||
@@ -52,27 +61,29 @@ namespace Lidgren.Network
|
|||||||
internal override NetSendResult Enqueue(NetOutgoingMessage message)
|
internal override NetSendResult Enqueue(NetOutgoingMessage message)
|
||||||
{
|
{
|
||||||
m_queuedSends.Enqueue(message);
|
m_queuedSends.Enqueue(message);
|
||||||
|
m_connection.m_peer.m_needFlushSendQueue = true; // a race condition to this variable will simply result in a single superflous call to FlushSendQueue()
|
||||||
int queueLen = m_queuedSends.Count;
|
if (m_queuedSends.Count <= GetAllowedSends())
|
||||||
int left = m_windowSize - ((m_sendStart + NetConstants.NumSequenceNumbers) - m_windowStart) % NetConstants.NumSequenceNumbers;
|
|
||||||
if (queueLen <= left)
|
|
||||||
return NetSendResult.Sent;
|
return NetSendResult.Sent;
|
||||||
return NetSendResult.Queued;
|
return NetSendResult.Queued;
|
||||||
}
|
}
|
||||||
|
|
||||||
// call this regularely
|
// call this regularely
|
||||||
internal override void SendQueuedMessages(float now)
|
internal override void SendQueuedMessages(double now)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// resends
|
// resends
|
||||||
//
|
//
|
||||||
|
m_anyStoredResends = false;
|
||||||
for (int i = 0; i < m_storedMessages.Length; i++)
|
for (int i = 0; i < m_storedMessages.Length; i++)
|
||||||
{
|
{
|
||||||
NetOutgoingMessage om = m_storedMessages[i].Message;
|
var storedMsg = m_storedMessages[i];
|
||||||
|
NetOutgoingMessage om = storedMsg.Message;
|
||||||
if (om == null)
|
if (om == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
float t = m_storedMessages[i].LastSent;
|
m_anyStoredResends = true;
|
||||||
|
|
||||||
|
double t = storedMsg.LastSent;
|
||||||
if (t > 0 && (now - t) > m_resendDelay)
|
if (t > 0 && (now - t) > m_resendDelay)
|
||||||
{
|
{
|
||||||
// deduce sequence number
|
// deduce sequence number
|
||||||
@@ -91,7 +102,8 @@ namespace Lidgren.Network
|
|||||||
//m_connection.m_peer.LogVerbose("Resending due to delay #" + m_storedMessages[i].SequenceNumber + " " + om.ToString());
|
//m_connection.m_peer.LogVerbose("Resending due to delay #" + m_storedMessages[i].SequenceNumber + " " + om.ToString());
|
||||||
m_connection.m_statistics.MessageResent(MessageResendReason.Delay);
|
m_connection.m_statistics.MessageResent(MessageResendReason.Delay);
|
||||||
|
|
||||||
m_connection.QueueSendMessage(om, m_storedMessages[i].SequenceNumber);
|
Interlocked.Increment(ref om.m_recyclingCount); // increment this since it's being decremented in QueueSendMessage
|
||||||
|
m_connection.QueueSendMessage(om, storedMsg.SequenceNumber);
|
||||||
|
|
||||||
m_storedMessages[i].LastSent = now;
|
m_storedMessages[i].LastSent = now;
|
||||||
m_storedMessages[i].NumSent++;
|
m_storedMessages[i].NumSent++;
|
||||||
@@ -103,7 +115,7 @@ namespace Lidgren.Network
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// queued sends
|
// queued sends
|
||||||
while (m_queuedSends.Count > 0 && num > 0)
|
while (num > 0 && m_queuedSends.Count > 0)
|
||||||
{
|
{
|
||||||
NetOutgoingMessage om;
|
NetOutgoingMessage om;
|
||||||
if (m_queuedSends.TryDequeue(out om))
|
if (m_queuedSends.TryDequeue(out om))
|
||||||
@@ -112,12 +124,16 @@ namespace Lidgren.Network
|
|||||||
NetException.Assert(num == GetAllowedSends());
|
NetException.Assert(num == GetAllowedSends());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExecuteSend(float now, NetOutgoingMessage message)
|
private void ExecuteSend(double now, NetOutgoingMessage message)
|
||||||
{
|
{
|
||||||
int seqNr = m_sendStart;
|
int seqNr = m_sendStart;
|
||||||
m_sendStart = (m_sendStart + 1) % NetConstants.NumSequenceNumbers;
|
m_sendStart = (m_sendStart + 1) % NetConstants.NumSequenceNumbers;
|
||||||
|
|
||||||
|
// must increment recycle count here, since it's decremented in QueueSendMessage and we want to keep it for the future in case or resends
|
||||||
|
// we will decrement once more in DestoreMessage for final recycling
|
||||||
|
Interlocked.Increment(ref message.m_recyclingCount);
|
||||||
|
|
||||||
m_connection.QueueSendMessage(message, seqNr);
|
m_connection.QueueSendMessage(message, seqNr);
|
||||||
|
|
||||||
int storeIndex = seqNr % m_windowSize;
|
int storeIndex = seqNr % m_windowSize;
|
||||||
@@ -127,13 +143,22 @@ namespace Lidgren.Network
|
|||||||
m_storedMessages[storeIndex].Message = message;
|
m_storedMessages[storeIndex].Message = message;
|
||||||
m_storedMessages[storeIndex].LastSent = now;
|
m_storedMessages[storeIndex].LastSent = now;
|
||||||
m_storedMessages[storeIndex].SequenceNumber = seqNr;
|
m_storedMessages[storeIndex].SequenceNumber = seqNr;
|
||||||
|
m_anyStoredResends = true;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DestoreMessage(int storeIndex)
|
private void DestoreMessage(double now, int storeIndex, out bool resetTimeout)
|
||||||
{
|
{
|
||||||
NetOutgoingMessage storedMessage = m_storedMessages[storeIndex].Message;
|
// reset timeout if we receive ack within kThreshold of sending it
|
||||||
|
const double kThreshold = 2.0;
|
||||||
|
var srm = m_storedMessages[storeIndex];
|
||||||
|
resetTimeout = (srm.NumSent == 1) && (now - srm.LastSent < kThreshold);
|
||||||
|
|
||||||
|
var storedMessage = srm.Message;
|
||||||
|
|
||||||
|
// on each destore; reduce recyclingcount so that when all instances are destored, the outgoing message can be recycled
|
||||||
|
Interlocked.Decrement(ref storedMessage.m_recyclingCount);
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (storedMessage == null)
|
if (storedMessage == null)
|
||||||
throw new NetException("m_storedMessages[" + storeIndex + "].Message is null; sent " + m_storedMessages[storeIndex].NumSent + " times, last time " + (NetTime.Now - m_storedMessages[storeIndex].LastSent) + " seconds ago");
|
throw new NetException("m_storedMessages[" + storeIndex + "].Message is null; sent " + m_storedMessages[storeIndex].NumSent + " times, last time " + (NetTime.Now - m_storedMessages[storeIndex].LastSent) + " seconds ago");
|
||||||
@@ -141,7 +166,6 @@ namespace Lidgren.Network
|
|||||||
if (storedMessage != null)
|
if (storedMessage != null)
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
Interlocked.Decrement(ref storedMessage.m_recyclingCount);
|
|
||||||
if (storedMessage.m_recyclingCount <= 0)
|
if (storedMessage.m_recyclingCount <= 0)
|
||||||
m_connection.m_peer.Recycle(storedMessage);
|
m_connection.m_peer.Recycle(storedMessage);
|
||||||
|
|
||||||
@@ -153,7 +177,7 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
// remoteWindowStart is remote expected sequence number; everything below this has arrived properly
|
// remoteWindowStart is remote expected sequence number; everything below this has arrived properly
|
||||||
// seqNr is the actual nr received
|
// seqNr is the actual nr received
|
||||||
internal override void ReceiveAcknowledge(float now, int seqNr)
|
internal override void ReceiveAcknowledge(double now, int seqNr)
|
||||||
{
|
{
|
||||||
// late (dupe), on time or early ack?
|
// late (dupe), on time or early ack?
|
||||||
int relate = NetUtility.RelativeSequenceNumber(seqNr, m_windowStart);
|
int relate = NetUtility.RelativeSequenceNumber(seqNr, m_windowStart);
|
||||||
@@ -171,8 +195,9 @@ namespace Lidgren.Network
|
|||||||
// ack arrived right on time
|
// ack arrived right on time
|
||||||
NetException.Assert(seqNr == m_windowStart);
|
NetException.Assert(seqNr == m_windowStart);
|
||||||
|
|
||||||
|
bool resetTimeout;
|
||||||
m_receivedAcks[m_windowStart] = false;
|
m_receivedAcks[m_windowStart] = false;
|
||||||
DestoreMessage(m_windowStart % m_windowSize);
|
DestoreMessage(now, m_windowStart % m_windowSize, out resetTimeout);
|
||||||
m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers;
|
m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers;
|
||||||
|
|
||||||
// advance window if we already have early acks
|
// advance window if we already have early acks
|
||||||
@@ -180,13 +205,16 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
//m_connection.m_peer.LogDebug("Using early ack for #" + m_windowStart + "...");
|
//m_connection.m_peer.LogDebug("Using early ack for #" + m_windowStart + "...");
|
||||||
m_receivedAcks[m_windowStart] = false;
|
m_receivedAcks[m_windowStart] = false;
|
||||||
DestoreMessage(m_windowStart % m_windowSize);
|
bool rt;
|
||||||
|
DestoreMessage(now, m_windowStart % m_windowSize, out rt);
|
||||||
|
resetTimeout |= rt;
|
||||||
|
|
||||||
NetException.Assert(m_storedMessages[m_windowStart % m_windowSize].Message == null); // should already be destored
|
NetException.Assert(m_storedMessages[m_windowStart % m_windowSize].Message == null); // should already be destored
|
||||||
m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers;
|
m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers;
|
||||||
//m_connection.m_peer.LogDebug("Advancing window to #" + m_windowStart);
|
//m_connection.m_peer.LogDebug("Advancing window to #" + m_windowStart);
|
||||||
}
|
}
|
||||||
|
if (resetTimeout)
|
||||||
|
m_connection.ResetTimeout(now);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,7 +269,7 @@ namespace Lidgren.Network
|
|||||||
NetOutgoingMessage rmsg = m_storedMessages[slot].Message;
|
NetOutgoingMessage rmsg = m_storedMessages[slot].Message;
|
||||||
//m_connection.m_peer.LogVerbose("Resending #" + rnr + " (" + rmsg + ")");
|
//m_connection.m_peer.LogVerbose("Resending #" + rnr + " (" + rmsg + ")");
|
||||||
|
|
||||||
if (now - m_storedMessages[slot].LastSent < (m_resendDelay * 0.35f))
|
if (now - m_storedMessages[slot].LastSent < (m_resendDelay * 0.35))
|
||||||
{
|
{
|
||||||
// already resent recently
|
// already resent recently
|
||||||
}
|
}
|
||||||
@@ -250,6 +278,7 @@ namespace Lidgren.Network
|
|||||||
m_storedMessages[slot].LastSent = now;
|
m_storedMessages[slot].LastSent = now;
|
||||||
m_storedMessages[slot].NumSent++;
|
m_storedMessages[slot].NumSent++;
|
||||||
m_connection.m_statistics.MessageResent(MessageResendReason.HoleInSequence);
|
m_connection.m_statistics.MessageResent(MessageResendReason.HoleInSequence);
|
||||||
|
Interlocked.Increment(ref rmsg.m_recyclingCount); // increment this since it's being decremented in QueueSendMessage
|
||||||
m_connection.QueueSendMessage(rmsg, rnr);
|
m_connection.QueueSendMessage(rmsg, rnr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
if (relate < 0)
|
if (relate < 0)
|
||||||
{
|
{
|
||||||
|
m_connection.m_statistics.MessageDropped();
|
||||||
m_peer.LogVerbose("Received message #" + message.m_sequenceNumber + " DROPPING LATE or DUPE");
|
m_peer.LogVerbose("Received message #" + message.m_sequenceNumber + " DROPPING LATE or DUPE");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -50,6 +51,7 @@ namespace Lidgren.Network
|
|||||||
if (relate > m_windowSize)
|
if (relate > m_windowSize)
|
||||||
{
|
{
|
||||||
// too early message!
|
// too early message!
|
||||||
|
m_connection.m_statistics.MessageDropped();
|
||||||
m_peer.LogDebug("Received " + message + " TOO EARLY! Expected " + m_windowStart);
|
m_peer.LogDebug("Received " + message + " TOO EARLY! Expected " + m_windowStart);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ namespace Lidgren.Network
|
|||||||
if (relate < 0)
|
if (relate < 0)
|
||||||
{
|
{
|
||||||
// duplicate
|
// duplicate
|
||||||
|
m_connection.m_statistics.MessageDropped();
|
||||||
m_peer.LogVerbose("Received message #" + message.m_sequenceNumber + " DROPPING DUPLICATE");
|
m_peer.LogVerbose("Received message #" + message.m_sequenceNumber + " DROPPING DUPLICATE");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -73,10 +74,19 @@ namespace Lidgren.Network
|
|||||||
if (relate > m_windowSize)
|
if (relate > m_windowSize)
|
||||||
{
|
{
|
||||||
// too early message!
|
// too early message!
|
||||||
|
m_connection.m_statistics.MessageDropped();
|
||||||
m_peer.LogDebug("Received " + message + " TOO EARLY! Expected " + m_windowStart);
|
m_peer.LogDebug("Received " + message + " TOO EARLY! Expected " + m_windowStart);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_earlyReceived.Get(message.m_sequenceNumber % m_windowSize))
|
||||||
|
{
|
||||||
|
// duplicate
|
||||||
|
m_connection.m_statistics.MessageDropped();
|
||||||
|
m_peer.LogVerbose("Received message #" + message.m_sequenceNumber + " DROPPING DUPLICATE");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_earlyReceived.Set(message.m_sequenceNumber % m_windowSize, true);
|
m_earlyReceived.Set(message.m_sequenceNumber % m_windowSize, true);
|
||||||
//m_peer.LogVerbose("Received " + message + " WITHHOLDING, waiting for " + m_windowStart);
|
//m_peer.LogVerbose("Received " + message + " WITHHOLDING, waiting for " + m_windowStart);
|
||||||
//m_withheldMessages[message.m_sequenceNumber % m_windowSize] = message;
|
//m_withheldMessages[message.m_sequenceNumber % m_windowSize] = message;
|
||||||
|
|||||||
+10
-35
@@ -14,17 +14,7 @@ namespace Lidgren.Network
|
|||||||
private static readonly NetBigInteger N = new NetBigInteger("0115b8b692e0e045692cf280b436735c77a5a9e8a9e7ed56c965f87db5b2a2ece3", 16);
|
private static readonly NetBigInteger N = new NetBigInteger("0115b8b692e0e045692cf280b436735c77a5a9e8a9e7ed56c965f87db5b2a2ece3", 16);
|
||||||
private static readonly NetBigInteger g = NetBigInteger.Two;
|
private static readonly NetBigInteger g = NetBigInteger.Two;
|
||||||
private static readonly NetBigInteger k = ComputeMultiplier();
|
private static readonly NetBigInteger k = ComputeMultiplier();
|
||||||
|
|
||||||
private static HashAlgorithm GetHashAlgorithm()
|
|
||||||
{
|
|
||||||
#if USE_SHA256
|
|
||||||
// this does not seem to work as of yet
|
|
||||||
return SHA256.Create();
|
|
||||||
#else
|
|
||||||
return SHA1.Create();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compute multiplier (k)
|
/// Compute multiplier (k)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -36,9 +26,7 @@ namespace Lidgren.Network
|
|||||||
string ccstr = one + two.PadLeft(one.Length, '0');
|
string ccstr = one + two.PadLeft(one.Length, '0');
|
||||||
byte[] cc = NetUtility.ToByteArray(ccstr);
|
byte[] cc = NetUtility.ToByteArray(ccstr);
|
||||||
|
|
||||||
var sha = GetHashAlgorithm();
|
var ccHashed = NetUtility.ComputeSHAHash(cc);
|
||||||
var ccHashed = sha.ComputeHash(cc);
|
|
||||||
|
|
||||||
return new NetBigInteger(NetUtility.ToHexString(ccHashed), 16);
|
return new NetBigInteger(NetUtility.ToHexString(ccHashed), 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +36,7 @@ namespace Lidgren.Network
|
|||||||
public static byte[] CreateRandomSalt()
|
public static byte[] CreateRandomSalt()
|
||||||
{
|
{
|
||||||
byte[] retval = new byte[16];
|
byte[] retval = new byte[16];
|
||||||
NetRandom.Instance.NextBytes(retval);
|
CryptoRandom.Instance.NextBytes(retval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +46,7 @@ namespace Lidgren.Network
|
|||||||
public static byte[] CreateRandomEphemeral()
|
public static byte[] CreateRandomEphemeral()
|
||||||
{
|
{
|
||||||
byte[] retval = new byte[32];
|
byte[] retval = new byte[32];
|
||||||
NetRandom.Instance.NextBytes(retval);
|
CryptoRandom.Instance.NextBytes(retval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,17 +55,15 @@ namespace Lidgren.Network
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static byte[] ComputePrivateKey(string username, string password, byte[] salt)
|
public static byte[] ComputePrivateKey(string username, string password, byte[] salt)
|
||||||
{
|
{
|
||||||
var sha = GetHashAlgorithm();
|
|
||||||
|
|
||||||
byte[] tmp = Encoding.UTF8.GetBytes(username + ":" + password);
|
byte[] tmp = Encoding.UTF8.GetBytes(username + ":" + password);
|
||||||
byte[] innerHash = sha.ComputeHash(tmp);
|
byte[] innerHash = NetUtility.ComputeSHAHash(tmp);
|
||||||
|
|
||||||
byte[] total = new byte[innerHash.Length + salt.Length];
|
byte[] total = new byte[innerHash.Length + salt.Length];
|
||||||
Buffer.BlockCopy(salt, 0, total, 0, salt.Length);
|
Buffer.BlockCopy(salt, 0, total, 0, salt.Length);
|
||||||
Buffer.BlockCopy(innerHash, 0, total, salt.Length, innerHash.Length);
|
Buffer.BlockCopy(innerHash, 0, total, salt.Length, innerHash.Length);
|
||||||
|
|
||||||
// x ie. H(salt || H(username || ":" || password))
|
// x ie. H(salt || H(username || ":" || password))
|
||||||
return new NetBigInteger(NetUtility.ToHexString(sha.ComputeHash(total)), 16).ToByteArrayUnsigned();
|
return new NetBigInteger(NetUtility.ToHexString(NetUtility.ComputeSHAHash(total)), 16).ToByteArrayUnsigned();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -93,15 +79,6 @@ namespace Lidgren.Network
|
|||||||
return serverVerifier.ToByteArrayUnsigned();
|
return serverVerifier.ToByteArrayUnsigned();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// SHA hash data
|
|
||||||
/// </summary>
|
|
||||||
public static byte[] Hash(byte[] data)
|
|
||||||
{
|
|
||||||
var sha = GetHashAlgorithm();
|
|
||||||
return sha.ComputeHash(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compute client public ephemeral value (A)
|
/// Compute client public ephemeral value (A)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -144,8 +121,7 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
byte[] cc = NetUtility.ToByteArray(ccstr);
|
byte[] cc = NetUtility.ToByteArray(ccstr);
|
||||||
|
|
||||||
var sha = GetHashAlgorithm();
|
var ccHashed = NetUtility.ComputeSHAHash(cc);
|
||||||
var ccHashed = sha.ComputeHash(cc);
|
|
||||||
|
|
||||||
return new NetBigInteger(NetUtility.ToHexString(ccHashed), 16).ToByteArrayUnsigned();
|
return new NetBigInteger(NetUtility.ToHexString(ccHashed), 16).ToByteArrayUnsigned();
|
||||||
}
|
}
|
||||||
@@ -185,10 +161,9 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create XTEA symmetrical encryption object from sessionValue
|
/// Create XTEA symmetrical encryption object from sessionValue
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static NetXtea CreateEncryption(byte[] sessionValue)
|
public static NetXtea CreateEncryption(NetPeer peer, byte[] sessionValue)
|
||||||
{
|
{
|
||||||
var sha = GetHashAlgorithm();
|
var hash = NetUtility.ComputeSHAHash(sessionValue);
|
||||||
var hash = sha.ComputeHash(sessionValue);
|
|
||||||
|
|
||||||
var key = new byte[16];
|
var key = new byte[16];
|
||||||
for(int i=0;i<16;i++)
|
for(int i=0;i<16;i++)
|
||||||
@@ -198,7 +173,7 @@ namespace Lidgren.Network
|
|||||||
key[i] ^= hash[i + (j * 16)];
|
key[i] ^= hash[i + (j * 16)];
|
||||||
}
|
}
|
||||||
|
|
||||||
return new NetXtea(key);
|
return new NetXtea(peer, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,15 +5,24 @@ namespace Lidgren.Network
|
|||||||
internal abstract class NetSenderChannelBase
|
internal abstract class NetSenderChannelBase
|
||||||
{
|
{
|
||||||
// access this directly to queue things in this channel
|
// access this directly to queue things in this channel
|
||||||
internal NetQueue<NetOutgoingMessage> m_queuedSends;
|
protected NetQueue<NetOutgoingMessage> m_queuedSends;
|
||||||
|
|
||||||
internal abstract int WindowSize { get; }
|
internal abstract int WindowSize { get; }
|
||||||
|
|
||||||
internal abstract int GetAllowedSends();
|
internal abstract int GetAllowedSends();
|
||||||
|
|
||||||
|
internal int QueuedSendsCount { get { return m_queuedSends.Count; } }
|
||||||
|
|
||||||
|
internal virtual bool NeedToSendMessages() { return m_queuedSends.Count > 0; }
|
||||||
|
|
||||||
|
public int GetFreeWindowSlots()
|
||||||
|
{
|
||||||
|
return GetAllowedSends() - m_queuedSends.Count;
|
||||||
|
}
|
||||||
|
|
||||||
internal abstract NetSendResult Enqueue(NetOutgoingMessage message);
|
internal abstract NetSendResult Enqueue(NetOutgoingMessage message);
|
||||||
internal abstract void SendQueuedMessages(float now);
|
internal abstract void SendQueuedMessages(double now);
|
||||||
internal abstract void Reset();
|
internal abstract void Reset();
|
||||||
internal abstract void ReceiveAcknowledge(float now, int sequenceNumber);
|
internal abstract void ReceiveAcknowledge(double now, int sequenceNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ namespace Lidgren.Network
|
|||||||
internal struct NetStoredReliableMessage
|
internal struct NetStoredReliableMessage
|
||||||
{
|
{
|
||||||
public int NumSent;
|
public int NumSent;
|
||||||
public float LastSent;
|
public double LastSent;
|
||||||
public NetOutgoingMessage Message;
|
public NetOutgoingMessage Message;
|
||||||
public int SequenceNumber;
|
public int SequenceNumber;
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
NumSent = 0;
|
NumSent = 0;
|
||||||
LastSent = 0;
|
LastSent = 0.0;
|
||||||
Message = null;
|
Message = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR TH
|
|||||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#define IS_STOPWATCH_AVAILABLE
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -29,25 +27,8 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Time service
|
/// Time service
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class NetTime
|
public static partial class NetTime
|
||||||
{
|
{
|
||||||
#if IS_STOPWATCH_AVAILABLE
|
|
||||||
private static readonly long s_timeInitialized = Stopwatch.GetTimestamp();
|
|
||||||
private static readonly double s_dInvFreq = 1.0 / (double)Stopwatch.Frequency;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get number of seconds since the application started
|
|
||||||
/// </summary>
|
|
||||||
public static double Now { get { return (double)(Stopwatch.GetTimestamp() - s_timeInitialized) * s_dInvFreq; } }
|
|
||||||
#else
|
|
||||||
private static readonly uint s_timeInitialized = (uint)Environment.TickCount;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get number of seconds since the application started
|
|
||||||
/// </summary>
|
|
||||||
public static double Now { get { return (double)((uint)Environment.TickCount - s_timeInitialized) / 1000.0; } }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Given seconds it will output a human friendly readable string (milliseconds if less than 60 seconds)
|
/// Given seconds it will output a human friendly readable string (milliseconds if less than 60 seconds)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
+30
-20
@@ -5,6 +5,10 @@ using System.Net;
|
|||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
|
#if !__NOIPENDPOINT__
|
||||||
|
using NetEndPoint = System.Net.IPEndPoint;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -40,7 +44,7 @@ namespace Lidgren.Network
|
|||||||
private NetPeer m_peer;
|
private NetPeer m_peer;
|
||||||
private ManualResetEvent m_discoveryComplete = new ManualResetEvent(false);
|
private ManualResetEvent m_discoveryComplete = new ManualResetEvent(false);
|
||||||
|
|
||||||
internal float m_discoveryResponseDeadline;
|
internal double m_discoveryResponseDeadline;
|
||||||
|
|
||||||
private UPnPStatus m_status;
|
private UPnPStatus m_status;
|
||||||
|
|
||||||
@@ -55,7 +59,7 @@ namespace Lidgren.Network
|
|||||||
public NetUPnP(NetPeer peer)
|
public NetUPnP(NetPeer peer)
|
||||||
{
|
{
|
||||||
m_peer = peer;
|
m_peer = peer;
|
||||||
m_discoveryResponseDeadline = float.MinValue;
|
m_discoveryResponseDeadline = double.MinValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Discover(NetPeer peer)
|
internal void Discover(NetPeer peer)
|
||||||
@@ -67,22 +71,25 @@ namespace Lidgren.Network
|
|||||||
"MAN:\"ssdp:discover\"\r\n" +
|
"MAN:\"ssdp:discover\"\r\n" +
|
||||||
"MX:3\r\n\r\n";
|
"MX:3\r\n\r\n";
|
||||||
|
|
||||||
|
m_discoveryResponseDeadline = NetTime.Now + 6.0; // arbitrarily chosen number, router gets 6 seconds to respond
|
||||||
m_status = UPnPStatus.Discovering;
|
m_status = UPnPStatus.Discovering;
|
||||||
|
|
||||||
byte[] arr = System.Text.Encoding.UTF8.GetBytes(str);
|
byte[] arr = System.Text.Encoding.UTF8.GetBytes(str);
|
||||||
|
|
||||||
m_peer.LogDebug("Attempting UPnP discovery");
|
m_peer.LogDebug("Attempting UPnP discovery");
|
||||||
peer.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
|
peer.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
|
||||||
peer.RawSend(arr, 0, arr.Length, new IPEndPoint(IPAddress.Broadcast, 1900));
|
peer.RawSend(arr, 0, arr.Length, new NetEndPoint(NetUtility.GetBroadcastAddress(), 1900));
|
||||||
peer.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, false);
|
peer.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, false);
|
||||||
|
|
||||||
// allow some extra time for router to respond
|
|
||||||
// System.Threading.Thread.Sleep(50);
|
|
||||||
|
|
||||||
m_discoveryResponseDeadline = (float)NetTime.Now + 6.0f; // arbitrarily chosen number, router gets 6 seconds to respond
|
|
||||||
m_status = UPnPStatus.Discovering;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void CheckForDiscoveryTimeout()
|
||||||
|
{
|
||||||
|
if ((m_status != UPnPStatus.Discovering) || (NetTime.Now < m_discoveryResponseDeadline))
|
||||||
|
return;
|
||||||
|
m_peer.LogDebug("UPnP discovery timed out");
|
||||||
|
m_status = UPnPStatus.NotAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
internal void ExtractServiceUrl(string resp)
|
internal void ExtractServiceUrl(string resp)
|
||||||
{
|
{
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
@@ -90,7 +97,9 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
XmlDocument desc = new XmlDocument();
|
XmlDocument desc = new XmlDocument();
|
||||||
desc.Load(WebRequest.Create(resp).GetResponse().GetResponseStream());
|
using (var response = WebRequest.Create(resp).GetResponse())
|
||||||
|
desc.Load(response.GetResponseStream());
|
||||||
|
|
||||||
XmlNamespaceManager nsMgr = new XmlNamespaceManager(desc.NameTable);
|
XmlNamespaceManager nsMgr = new XmlNamespaceManager(desc.NameTable);
|
||||||
nsMgr.AddNamespace("tns", "urn:schemas-upnp-org:device-1-0");
|
nsMgr.AddNamespace("tns", "urn:schemas-upnp-org:device-1-0");
|
||||||
XmlNode typen = desc.SelectSingleNode("//tns:device/tns:deviceType/text()", nsMgr);
|
XmlNode typen = desc.SelectSingleNode("//tns:device/tns:deviceType/text()", nsMgr);
|
||||||
@@ -168,11 +177,11 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
XmlDocument xdoc = SOAPRequest(m_serviceUrl,
|
SOAPRequest(m_serviceUrl,
|
||||||
"<u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:" + m_serviceName + ":1\">" +
|
"<u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:" + m_serviceName + ":1\">" +
|
||||||
"<NewRemoteHost></NewRemoteHost>" +
|
"<NewRemoteHost></NewRemoteHost>" +
|
||||||
"<NewExternalPort>" + port.ToString() + "</NewExternalPort>" +
|
"<NewExternalPort>" + port.ToString() + "</NewExternalPort>" +
|
||||||
"<NewProtocol>" + ProtocolType.Udp.ToString().ToUpper() + "</NewProtocol>" +
|
"<NewProtocol>" + ProtocolType.Udp.ToString().ToUpper(System.Globalization.CultureInfo.InvariantCulture) + "</NewProtocol>" +
|
||||||
"<NewInternalPort>" + port.ToString() + "</NewInternalPort>" +
|
"<NewInternalPort>" + port.ToString() + "</NewInternalPort>" +
|
||||||
"<NewInternalClient>" + client.ToString() + "</NewInternalClient>" +
|
"<NewInternalClient>" + client.ToString() + "</NewInternalClient>" +
|
||||||
"<NewEnabled>1</NewEnabled>" +
|
"<NewEnabled>1</NewEnabled>" +
|
||||||
@@ -182,7 +191,7 @@ namespace Lidgren.Network
|
|||||||
"AddPortMapping");
|
"AddPortMapping");
|
||||||
|
|
||||||
m_peer.LogDebug("Sent UPnP port forward request");
|
m_peer.LogDebug("Sent UPnP port forward request");
|
||||||
System.Threading.Thread.Sleep(50);
|
NetUtility.Sleep(50);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -202,12 +211,12 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
XmlDocument xdoc = SOAPRequest(m_serviceUrl,
|
SOAPRequest(m_serviceUrl,
|
||||||
"<u:DeletePortMapping xmlns:u=\"urn:schemas-upnp-org:service:" + m_serviceName + ":1\">" +
|
"<u:DeletePortMapping xmlns:u=\"urn:schemas-upnp-org:service:" + m_serviceName + ":1\">" +
|
||||||
"<NewRemoteHost>" +
|
"<NewRemoteHost>" +
|
||||||
"</NewRemoteHost>" +
|
"</NewRemoteHost>" +
|
||||||
"<NewExternalPort>" + port + "</NewExternalPort>" +
|
"<NewExternalPort>" + port + "</NewExternalPort>" +
|
||||||
"<NewProtocol>" + ProtocolType.Udp.ToString().ToUpper() + "</NewProtocol>" +
|
"<NewProtocol>" + ProtocolType.Udp.ToString().ToUpper(System.Globalization.CultureInfo.InvariantCulture) + "</NewProtocol>" +
|
||||||
"</u:DeletePortMapping>", "DeletePortMapping");
|
"</u:DeletePortMapping>", "DeletePortMapping");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -256,11 +265,12 @@ namespace Lidgren.Network
|
|||||||
r.ContentType = "text/xml; charset=\"utf-8\"";
|
r.ContentType = "text/xml; charset=\"utf-8\"";
|
||||||
r.ContentLength = b.Length;
|
r.ContentLength = b.Length;
|
||||||
r.GetRequestStream().Write(b, 0, b.Length);
|
r.GetRequestStream().Write(b, 0, b.Length);
|
||||||
XmlDocument resp = new XmlDocument();
|
using (WebResponse wres = r.GetResponse()) {
|
||||||
WebResponse wres = r.GetResponse();
|
XmlDocument resp = new XmlDocument();
|
||||||
Stream ress = wres.GetResponseStream();
|
Stream ress = wres.GetResponseStream();
|
||||||
resp.Load(ress);
|
resp.Load(ress);
|
||||||
return resp;
|
return resp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,12 +12,13 @@ namespace Lidgren.Network
|
|||||||
private int m_windowStart;
|
private int m_windowStart;
|
||||||
private int m_windowSize;
|
private int m_windowSize;
|
||||||
private int m_sendStart;
|
private int m_sendStart;
|
||||||
|
private bool m_doFlowControl;
|
||||||
|
|
||||||
private NetBitVector m_receivedAcks;
|
private NetBitVector m_receivedAcks;
|
||||||
|
|
||||||
internal override int WindowSize { get { return m_windowSize; } }
|
internal override int WindowSize { get { return m_windowSize; } }
|
||||||
|
|
||||||
internal NetUnreliableSenderChannel(NetConnection connection, int windowSize)
|
internal NetUnreliableSenderChannel(NetConnection connection, int windowSize, NetDeliveryMethod method)
|
||||||
{
|
{
|
||||||
m_connection = connection;
|
m_connection = connection;
|
||||||
m_windowSize = windowSize;
|
m_windowSize = windowSize;
|
||||||
@@ -25,10 +26,16 @@ namespace Lidgren.Network
|
|||||||
m_sendStart = 0;
|
m_sendStart = 0;
|
||||||
m_receivedAcks = new NetBitVector(NetConstants.NumSequenceNumbers);
|
m_receivedAcks = new NetBitVector(NetConstants.NumSequenceNumbers);
|
||||||
m_queuedSends = new NetQueue<NetOutgoingMessage>(8);
|
m_queuedSends = new NetQueue<NetOutgoingMessage>(8);
|
||||||
|
|
||||||
|
m_doFlowControl = true;
|
||||||
|
if (method == NetDeliveryMethod.Unreliable && connection.Peer.Configuration.SuppressUnreliableUnorderedAcks == true)
|
||||||
|
m_doFlowControl = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override int GetAllowedSends()
|
internal override int GetAllowedSends()
|
||||||
{
|
{
|
||||||
|
if (!m_doFlowControl)
|
||||||
|
return 2; // always allowed to send without flow control!
|
||||||
int retval = m_windowSize - ((m_sendStart + NetConstants.NumSequenceNumbers) - m_windowStart) % m_windowSize;
|
int retval = m_windowSize - ((m_sendStart + NetConstants.NumSequenceNumbers) - m_windowStart) % m_windowSize;
|
||||||
NetException.Assert(retval >= 0 && retval <= m_windowSize);
|
NetException.Assert(retval >= 0 && retval <= m_windowSize);
|
||||||
return retval;
|
return retval;
|
||||||
@@ -45,23 +52,27 @@ namespace Lidgren.Network
|
|||||||
internal override NetSendResult Enqueue(NetOutgoingMessage message)
|
internal override NetSendResult Enqueue(NetOutgoingMessage message)
|
||||||
{
|
{
|
||||||
int queueLen = m_queuedSends.Count + 1;
|
int queueLen = m_queuedSends.Count + 1;
|
||||||
int left = m_windowSize - ((m_sendStart + NetConstants.NumSequenceNumbers) - m_windowStart) % NetConstants.NumSequenceNumbers;
|
int left = GetAllowedSends();
|
||||||
if (queueLen > left)
|
if (queueLen > left || (message.LengthBytes > m_connection.m_currentMTU && m_connection.m_peerConfiguration.UnreliableSizeBehaviour == NetUnreliableSizeBehaviour.DropAboveMTU))
|
||||||
|
{
|
||||||
|
// drop message
|
||||||
return NetSendResult.Dropped;
|
return NetSendResult.Dropped;
|
||||||
|
}
|
||||||
|
|
||||||
m_queuedSends.Enqueue(message);
|
m_queuedSends.Enqueue(message);
|
||||||
|
m_connection.m_peer.m_needFlushSendQueue = true; // a race condition to this variable will simply result in a single superflous call to FlushSendQueue()
|
||||||
return NetSendResult.Sent;
|
return NetSendResult.Sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// call this regularely
|
// call this regularely
|
||||||
internal override void SendQueuedMessages(float now)
|
internal override void SendQueuedMessages(double now)
|
||||||
{
|
{
|
||||||
int num = GetAllowedSends();
|
int num = GetAllowedSends();
|
||||||
if (num < 1)
|
if (num < 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// queued sends
|
// queued sends
|
||||||
while (m_queuedSends.Count > 0 && num > 0)
|
while (num > 0 && m_queuedSends.Count > 0)
|
||||||
{
|
{
|
||||||
NetOutgoingMessage om;
|
NetOutgoingMessage om;
|
||||||
if (m_queuedSends.TryDequeue(out om))
|
if (m_queuedSends.TryDequeue(out om))
|
||||||
@@ -79,7 +90,6 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
m_connection.QueueSendMessage(message, seqNr);
|
m_connection.QueueSendMessage(message, seqNr);
|
||||||
|
|
||||||
Interlocked.Decrement(ref message.m_recyclingCount);
|
|
||||||
if (message.m_recyclingCount <= 0)
|
if (message.m_recyclingCount <= 0)
|
||||||
m_connection.m_peer.Recycle(message);
|
m_connection.m_peer.Recycle(message);
|
||||||
|
|
||||||
@@ -88,8 +98,15 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
// remoteWindowStart is remote expected sequence number; everything below this has arrived properly
|
// remoteWindowStart is remote expected sequence number; everything below this has arrived properly
|
||||||
// seqNr is the actual nr received
|
// seqNr is the actual nr received
|
||||||
internal override void ReceiveAcknowledge(float now, int seqNr)
|
internal override void ReceiveAcknowledge(double now, int seqNr)
|
||||||
{
|
{
|
||||||
|
if (m_doFlowControl == false)
|
||||||
|
{
|
||||||
|
// we have no use for acks on this channel since we don't respect the window anyway
|
||||||
|
m_connection.m_peer.LogWarning("SuppressUnreliableUnorderedAcks sender/receiver mismatch!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// late (dupe), on time or early ack?
|
// late (dupe), on time or early ack?
|
||||||
int relate = NetUtility.RelativeSequenceNumber(seqNr, m_windowStart);
|
int relate = NetUtility.RelativeSequenceNumber(seqNr, m_windowStart);
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
internal sealed class NetUnreliableSequencedReceiver : NetReceiverChannelBase
|
internal sealed class NetUnreliableSequencedReceiver : NetReceiverChannelBase
|
||||||
{
|
{
|
||||||
private int m_lastReceivedSequenceNumber;
|
private int m_lastReceivedSequenceNumber = -1;
|
||||||
|
|
||||||
public NetUnreliableSequencedReceiver(NetConnection connection)
|
public NetUnreliableSequencedReceiver(NetConnection connection)
|
||||||
: base(connection)
|
: base(connection)
|
||||||
@@ -18,9 +18,13 @@ namespace Lidgren.Network
|
|||||||
// ack no matter what
|
// ack no matter what
|
||||||
m_connection.QueueAck(msg.m_receivedMessageType, nr);
|
m_connection.QueueAck(msg.m_receivedMessageType, nr);
|
||||||
|
|
||||||
int relate = NetUtility.RelativeSequenceNumber(nr, m_lastReceivedSequenceNumber);
|
int relate = NetUtility.RelativeSequenceNumber(nr, m_lastReceivedSequenceNumber + 1);
|
||||||
if (relate < 0)
|
if (relate < 0)
|
||||||
|
{
|
||||||
|
m_connection.m_statistics.MessageDropped();
|
||||||
|
m_peer.LogVerbose("Received message #" + nr + " DROPPING DUPLICATE");
|
||||||
return; // drop if late
|
return; // drop if late
|
||||||
|
}
|
||||||
|
|
||||||
m_lastReceivedSequenceNumber = nr;
|
m_lastReceivedSequenceNumber = nr;
|
||||||
m_peer.ReleaseMessage(msg);
|
m_peer.ReleaseMessage(msg);
|
||||||
|
|||||||
@@ -4,15 +4,18 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
internal sealed class NetUnreliableUnorderedReceiver : NetReceiverChannelBase
|
internal sealed class NetUnreliableUnorderedReceiver : NetReceiverChannelBase
|
||||||
{
|
{
|
||||||
|
private bool m_doFlowControl;
|
||||||
|
|
||||||
public NetUnreliableUnorderedReceiver(NetConnection connection)
|
public NetUnreliableUnorderedReceiver(NetConnection connection)
|
||||||
: base(connection)
|
: base(connection)
|
||||||
{
|
{
|
||||||
|
m_doFlowControl = connection.Peer.Configuration.SuppressUnreliableUnorderedAcks == false;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void ReceiveMessage(NetIncomingMessage msg)
|
internal override void ReceiveMessage(NetIncomingMessage msg)
|
||||||
{
|
{
|
||||||
// ack no matter what
|
if (m_doFlowControl)
|
||||||
m_connection.QueueAck(msg.m_receivedMessageType, msg.m_sequenceNumber);
|
m_connection.QueueAck(msg.m_receivedMessageType, msg.m_sequenceNumber);
|
||||||
|
|
||||||
m_peer.ReleaseMessage(msg);
|
m_peer.ReleaseMessage(msg);
|
||||||
}
|
}
|
||||||
|
|||||||
+53
-188
@@ -16,41 +16,46 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRA
|
|||||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#if !__ANDROID__ && !IOS
|
|
||||||
#define IS_FULL_NET_AVAILABLE
|
#if !__NOIPENDPOINT__
|
||||||
|
using NetEndPoint = System.Net.IPEndPoint;
|
||||||
|
using NetAddress = System.Net.IPAddress;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.NetworkInformation;
|
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Utility methods
|
/// Utility methods
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class NetUtility
|
public static partial class NetUtility
|
||||||
{
|
{
|
||||||
|
private static readonly bool IsMono = Type.GetType("Mono.Runtime") != null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resolve endpoint callback
|
/// Resolve endpoint callback
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public delegate void ResolveEndPointCallback(IPEndPoint endPoint);
|
public delegate void ResolveEndPointCallback(NetEndPoint endPoint);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resolve address callback
|
/// Resolve address callback
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public delegate void ResolveAddressCallback(IPAddress adr);
|
public delegate void ResolveAddressCallback(NetAddress adr);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get IPv4 endpoint from notation (xxx.xxx.xxx.xxx) or hostname and port number (asynchronous version)
|
/// Get IPv4 endpoint from notation (xxx.xxx.xxx.xxx) or hostname and port number (asynchronous version)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void ResolveAsync(string ipOrHost, int port, ResolveEndPointCallback callback)
|
public static void ResolveAsync(string ipOrHost, int port, ResolveEndPointCallback callback)
|
||||||
{
|
{
|
||||||
ResolveAsync(ipOrHost, delegate(IPAddress adr)
|
ResolveAsync(ipOrHost, delegate(NetAddress adr)
|
||||||
{
|
{
|
||||||
if (adr == null)
|
if (adr == null)
|
||||||
{
|
{
|
||||||
@@ -58,7 +63,7 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
callback(new IPEndPoint(adr, port));
|
callback(new NetEndPoint(adr, port));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -66,10 +71,18 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get IPv4 endpoint from notation (xxx.xxx.xxx.xxx) or hostname and port number
|
/// Get IPv4 endpoint from notation (xxx.xxx.xxx.xxx) or hostname and port number
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IPEndPoint Resolve(string ipOrHost, int port)
|
public static NetEndPoint Resolve(string ipOrHost, int port)
|
||||||
{
|
{
|
||||||
IPAddress adr = Resolve(ipOrHost);
|
var adr = Resolve(ipOrHost);
|
||||||
return new IPEndPoint(adr, port);
|
return adr == null ? null : new NetEndPoint(adr, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IPAddress s_broadcastAddress;
|
||||||
|
public static IPAddress GetCachedBroadcastAddress()
|
||||||
|
{
|
||||||
|
if (s_broadcastAddress == null)
|
||||||
|
s_broadcastAddress = GetBroadcastAddress();
|
||||||
|
return s_broadcastAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -82,8 +95,8 @@ namespace Lidgren.Network
|
|||||||
|
|
||||||
ipOrHost = ipOrHost.Trim();
|
ipOrHost = ipOrHost.Trim();
|
||||||
|
|
||||||
IPAddress ipAddress = null;
|
NetAddress ipAddress = null;
|
||||||
if (IPAddress.TryParse(ipOrHost, out ipAddress))
|
if (NetAddress.TryParse(ipOrHost, out ipAddress))
|
||||||
{
|
{
|
||||||
if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
|
if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
|
||||||
{
|
{
|
||||||
@@ -124,7 +137,7 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check each entry for a valid IP address
|
// check each entry for a valid IP address
|
||||||
foreach (IPAddress ipCurrent in entry.AddressList)
|
foreach (var ipCurrent in entry.AddressList)
|
||||||
{
|
{
|
||||||
if (ipCurrent.AddressFamily == AddressFamily.InterNetwork)
|
if (ipCurrent.AddressFamily == AddressFamily.InterNetwork)
|
||||||
{
|
{
|
||||||
@@ -153,15 +166,15 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get IPv4 address from notation (xxx.xxx.xxx.xxx) or hostname
|
/// Get IPv4 address from notation (xxx.xxx.xxx.xxx) or hostname
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IPAddress Resolve(string ipOrHost)
|
public static NetAddress Resolve(string ipOrHost)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(ipOrHost))
|
if (string.IsNullOrEmpty(ipOrHost))
|
||||||
throw new ArgumentException("Supplied string must not be empty", "ipOrHost");
|
throw new ArgumentException("Supplied string must not be empty", "ipOrHost");
|
||||||
|
|
||||||
ipOrHost = ipOrHost.Trim();
|
ipOrHost = ipOrHost.Trim();
|
||||||
|
|
||||||
IPAddress ipAddress = null;
|
NetAddress ipAddress = null;
|
||||||
if (IPAddress.TryParse(ipOrHost, out ipAddress))
|
if (NetAddress.TryParse(ipOrHost, out ipAddress))
|
||||||
{
|
{
|
||||||
if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
|
if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
|
||||||
return ipAddress;
|
return ipAddress;
|
||||||
@@ -195,56 +208,6 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if IS_FULL_NET_AVAILABLE
|
|
||||||
|
|
||||||
private static NetworkInterface GetNetworkInterface()
|
|
||||||
{
|
|
||||||
IPGlobalProperties computerProperties = IPGlobalProperties.GetIPGlobalProperties();
|
|
||||||
if (computerProperties == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
|
|
||||||
if (nics == null || nics.Length < 1)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
NetworkInterface best = null;
|
|
||||||
foreach (NetworkInterface adapter in nics)
|
|
||||||
{
|
|
||||||
if (adapter.NetworkInterfaceType == NetworkInterfaceType.Loopback || adapter.NetworkInterfaceType == NetworkInterfaceType.Unknown)
|
|
||||||
continue;
|
|
||||||
if (!adapter.Supports(NetworkInterfaceComponent.IPv4))
|
|
||||||
continue;
|
|
||||||
if (best == null)
|
|
||||||
best = adapter;
|
|
||||||
if (adapter.OperationalStatus != OperationalStatus.Up)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// make sure this adapter has any ipv4 addresses
|
|
||||||
IPInterfaceProperties properties = adapter.GetIPProperties();
|
|
||||||
foreach (UnicastIPAddressInformation unicastAddress in properties.UnicastAddresses)
|
|
||||||
{
|
|
||||||
if (unicastAddress != null && unicastAddress.Address != null && unicastAddress.Address.AddressFamily == AddressFamily.InterNetwork)
|
|
||||||
{
|
|
||||||
// Yes it does, return this network interface.
|
|
||||||
return adapter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return best;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the physical (MAC) address for the first usable network interface
|
|
||||||
/// </summary>
|
|
||||||
public static PhysicalAddress GetMacAddress()
|
|
||||||
{
|
|
||||||
NetworkInterface ni = GetNetworkInterface();
|
|
||||||
if (ni == null)
|
|
||||||
return null;
|
|
||||||
return ni.GetPhysicalAddress();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a hex string from an Int64 value
|
/// Create a hex string from an Int64 value
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -258,134 +221,30 @@ namespace Lidgren.Network
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static string ToHexString(byte[] data)
|
public static string ToHexString(byte[] data)
|
||||||
{
|
{
|
||||||
char[] c = new char[data.Length * 2];
|
return ToHexString(data, 0, data.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a hex string from an array of bytes
|
||||||
|
/// </summary>
|
||||||
|
public static string ToHexString(byte[] data, int offset, int length)
|
||||||
|
{
|
||||||
|
char[] c = new char[length * 2];
|
||||||
byte b;
|
byte b;
|
||||||
for (int i = 0; i < data.Length; ++i)
|
for (int i = 0; i < length; ++i)
|
||||||
{
|
{
|
||||||
b = ((byte)(data[i] >> 4));
|
b = ((byte)(data[offset + i] >> 4));
|
||||||
c[i * 2] = (char)(b > 9 ? b + 0x37 : b + 0x30);
|
c[i * 2] = (char)(b > 9 ? b + 0x37 : b + 0x30);
|
||||||
b = ((byte)(data[i] & 0xF));
|
b = ((byte)(data[offset + i] & 0xF));
|
||||||
c[i * 2 + 1] = (char)(b > 9 ? b + 0x37 : b + 0x30);
|
c[i * 2 + 1] = (char)(b > 9 ? b + 0x37 : b + 0x30);
|
||||||
}
|
}
|
||||||
return new string(c);
|
return new string(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the local broadcast address
|
|
||||||
/// </summary>
|
|
||||||
public static IPAddress GetBroadcastAddress()
|
|
||||||
{
|
|
||||||
#if __ANDROID__
|
|
||||||
try{
|
|
||||||
Android.Net.Wifi.WifiManager wifi = (Android.Net.Wifi.WifiManager)Android.App.Application.Context.GetSystemService(Android.App.Activity.WifiService);
|
|
||||||
if (wifi.IsWifiEnabled)
|
|
||||||
{
|
|
||||||
var dhcp = wifi.DhcpInfo;
|
|
||||||
|
|
||||||
int broadcast = (dhcp.IpAddress & dhcp.Netmask) | ~dhcp.Netmask;
|
|
||||||
byte[] quads = new byte[4];
|
|
||||||
for (int k = 0; k < 4; k++)
|
|
||||||
{
|
|
||||||
quads[k] = (byte) ((broadcast >> k * 8) & 0xFF);
|
|
||||||
}
|
|
||||||
return new IPAddress(quads);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch // Catch Access Denied Errors
|
|
||||||
{
|
|
||||||
return IPAddress.Broadcast;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if IS_FULL_NET_AVAILABLE
|
|
||||||
try
|
|
||||||
{
|
|
||||||
NetworkInterface ni = GetNetworkInterface();
|
|
||||||
if (ni == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPInterfaceProperties properties = ni.GetIPProperties();
|
|
||||||
foreach (UnicastIPAddressInformation unicastAddress in properties.UnicastAddresses)
|
|
||||||
{
|
|
||||||
if (unicastAddress != null && unicastAddress.Address != null && unicastAddress.Address.AddressFamily == AddressFamily.InterNetwork)
|
|
||||||
{
|
|
||||||
var mask = unicastAddress.IPv4Mask;
|
|
||||||
byte[] ipAdressBytes = unicastAddress.Address.GetAddressBytes();
|
|
||||||
byte[] subnetMaskBytes = mask.GetAddressBytes();
|
|
||||||
|
|
||||||
if (ipAdressBytes.Length != subnetMaskBytes.Length)
|
|
||||||
throw new ArgumentException("Lengths of IP address and subnet mask do not match.");
|
|
||||||
|
|
||||||
byte[] broadcastAddress = new byte[ipAdressBytes.Length];
|
|
||||||
for (int i = 0; i < broadcastAddress.Length; i++)
|
|
||||||
{
|
|
||||||
broadcastAddress[i] = (byte)(ipAdressBytes[i] | (subnetMaskBytes[i] ^ 255));
|
|
||||||
}
|
|
||||||
return new IPAddress(broadcastAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch // Catch any errors
|
|
||||||
{
|
|
||||||
return IPAddress.Broadcast;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return IPAddress.Broadcast;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets my local IPv4 address (not necessarily external) and subnet mask
|
/// Returns true if the endpoint supplied is on the same subnet as this host
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IPAddress GetMyAddress(out IPAddress mask)
|
public static bool IsLocal(NetEndPoint endPoint)
|
||||||
{
|
|
||||||
mask = null;
|
|
||||||
#if __ANDROID__
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Android.Net.Wifi.WifiManager wifi = (Android.Net.Wifi.WifiManager)Android.App.Application.Context.GetSystemService(Android.App.Activity.WifiService);
|
|
||||||
if (!wifi.IsWifiEnabled) return null;
|
|
||||||
var dhcp = wifi.DhcpInfo;
|
|
||||||
|
|
||||||
int addr = dhcp.IpAddress;
|
|
||||||
byte[] quads = new byte[4];
|
|
||||||
for (int k = 0; k < 4; k++)
|
|
||||||
{
|
|
||||||
quads[k] = (byte) ((addr >> k * 8) & 0xFF);
|
|
||||||
}
|
|
||||||
return new IPAddress(quads);
|
|
||||||
}
|
|
||||||
catch // Catch Access Denied errors
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#if IS_FULL_NET_AVAILABLE
|
|
||||||
NetworkInterface ni = GetNetworkInterface();
|
|
||||||
if (ni == null)
|
|
||||||
{
|
|
||||||
mask = null;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPInterfaceProperties properties = ni.GetIPProperties();
|
|
||||||
foreach (UnicastIPAddressInformation unicastAddress in properties.UnicastAddresses)
|
|
||||||
{
|
|
||||||
if (unicastAddress != null && unicastAddress.Address != null && unicastAddress.Address.AddressFamily == AddressFamily.InterNetwork)
|
|
||||||
{
|
|
||||||
mask = unicastAddress.IPv4Mask;
|
|
||||||
return unicastAddress.Address;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns true if the IPEndPoint supplied is on the same subnet as this host
|
|
||||||
/// </summary>
|
|
||||||
public static bool IsLocal(IPEndPoint endPoint)
|
|
||||||
{
|
{
|
||||||
if (endPoint == null)
|
if (endPoint == null)
|
||||||
return false;
|
return false;
|
||||||
@@ -395,10 +254,10 @@ namespace Lidgren.Network
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns true if the IPAddress supplied is on the same subnet as this host
|
/// Returns true if the IPAddress supplied is on the same subnet as this host
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool IsLocal(IPAddress remote)
|
public static bool IsLocal(NetAddress remote)
|
||||||
{
|
{
|
||||||
IPAddress mask;
|
NetAddress mask;
|
||||||
IPAddress local = GetMyAddress(out mask);
|
var local = GetMyAddress(out mask);
|
||||||
|
|
||||||
if (mask == null)
|
if (mask == null)
|
||||||
return false;
|
return false;
|
||||||
@@ -588,5 +447,11 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
return bdr.ToString();
|
return bdr.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] ComputeSHAHash(byte[] bytes)
|
||||||
|
{
|
||||||
|
// this is defined in the platform specific files
|
||||||
|
return ComputeSHAHash(bytes, 0, bytes.Length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
#if __ANDROID__
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace Lidgren.Network
|
||||||
|
{
|
||||||
|
public static partial class NetUtility
|
||||||
|
{
|
||||||
|
private static byte[] s_randomMacBytes;
|
||||||
|
|
||||||
|
static NetUtility()
|
||||||
|
{
|
||||||
|
s_randomMacBytes = new byte[8];
|
||||||
|
MWCRandom.Instance.NextBytes(s_randomMacBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static ulong GetPlatformSeed(int seedInc)
|
||||||
|
{
|
||||||
|
ulong seed = (ulong)Environment.TickCount + (ulong)seedInc;
|
||||||
|
return seed ^ ((ulong)(new object().GetHashCode()) << 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets my local IPv4 address (not necessarily external) and subnet mask
|
||||||
|
/// </summary>
|
||||||
|
public static IPAddress GetMyAddress(out IPAddress mask)
|
||||||
|
{
|
||||||
|
mask = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Android.Net.Wifi.WifiManager wifi = (Android.Net.Wifi.WifiManager)Android.App.Application.Context.GetSystemService(Android.App.Activity.WifiService);
|
||||||
|
if (!wifi.IsWifiEnabled)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var dhcp = wifi.DhcpInfo;
|
||||||
|
int addr = dhcp.IpAddress;
|
||||||
|
byte[] quads = new byte[4];
|
||||||
|
for (int k = 0; k < 4; k++)
|
||||||
|
quads[k] = (byte)((addr >> k * 8) & 0xFF);
|
||||||
|
return new IPAddress(quads);
|
||||||
|
}
|
||||||
|
catch // Catch Access Denied errors
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] GetMacAddressBytes()
|
||||||
|
{
|
||||||
|
return s_randomMacBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Sleep(int milliseconds)
|
||||||
|
{
|
||||||
|
System.Threading.Thread.Sleep(milliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IPAddress GetBroadcastAddress()
|
||||||
|
{
|
||||||
|
return IPAddress.Broadcast;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IPAddress CreateAddressFromBytes(byte[] bytes)
|
||||||
|
{
|
||||||
|
return new IPAddress(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly SHA1 s_sha = SHA1.Create();
|
||||||
|
public static byte[] ComputeSHAHash(byte[] bytes, int offset, int count)
|
||||||
|
{
|
||||||
|
return s_sha.ComputeHash(bytes, offset, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static partial class NetTime
|
||||||
|
{
|
||||||
|
private static readonly long s_timeInitialized = Environment.TickCount;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get number of seconds since the application started
|
||||||
|
/// </summary>
|
||||||
|
public static double Now { get { return (double)((uint)Environment.TickCount - s_timeInitialized) / 1000.0; } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
#if __CONSTRAINED__ || UNITY_STANDALONE_LINUX
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace Lidgren.Network
|
||||||
|
{
|
||||||
|
public static partial class NetUtility
|
||||||
|
{
|
||||||
|
private static byte[] s_randomMacBytes;
|
||||||
|
|
||||||
|
static NetUtility()
|
||||||
|
{
|
||||||
|
s_randomMacBytes = new byte[8];
|
||||||
|
MWCRandom.Instance.NextBytes(s_randomMacBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static ulong GetPlatformSeed(int seedInc)
|
||||||
|
{
|
||||||
|
ulong seed = (ulong)Environment.TickCount + (ulong)seedInc;
|
||||||
|
return seed ^ ((ulong)(new object().GetHashCode()) << 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets my local IPv4 address (not necessarily external) and subnet mask
|
||||||
|
/// </summary>
|
||||||
|
public static IPAddress GetMyAddress(out IPAddress mask)
|
||||||
|
{
|
||||||
|
mask = null;
|
||||||
|
#if UNITY_ANDROID || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_STANDALONE_LINUX || UNITY_IOS
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!(UnityEngine.Application.internetReachability == UnityEngine.NetworkReachability.NotReachable))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return IPAddress.Parse(UnityEngine.Network.player.externalIP);
|
||||||
|
}
|
||||||
|
catch // Catch Access Denied errors
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] GetMacAddressBytes()
|
||||||
|
{
|
||||||
|
return s_randomMacBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IPAddress GetBroadcastAddress()
|
||||||
|
{
|
||||||
|
return IPAddress.Broadcast;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Sleep(int milliseconds)
|
||||||
|
{
|
||||||
|
System.Threading.Thread.Sleep(milliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IPAddress CreateAddressFromBytes(byte[] bytes)
|
||||||
|
{
|
||||||
|
return new IPAddress(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly SHA1 s_sha = SHA1.Create();
|
||||||
|
public static byte[] ComputeSHAHash(byte[] bytes, int offset, int count)
|
||||||
|
{
|
||||||
|
return s_sha.ComputeHash(bytes, offset, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static partial class NetTime
|
||||||
|
{
|
||||||
|
private static readonly long s_timeInitialized = Environment.TickCount;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get number of seconds since the application started
|
||||||
|
/// </summary>
|
||||||
|
public static double Now { get { return (double)((uint)Environment.TickCount - s_timeInitialized) / 1000.0; } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
#if !__ANDROID__ && !__CONSTRAINED__ && !WINDOWS_RUNTIME && !UNITY_STANDALONE_LINUX
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.NetworkInformation;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace Lidgren.Network
|
||||||
|
{
|
||||||
|
public static partial class NetUtility
|
||||||
|
{
|
||||||
|
private static readonly long s_timeInitialized = Stopwatch.GetTimestamp();
|
||||||
|
private static readonly double s_dInvFreq = 1.0 / (double)Stopwatch.Frequency;
|
||||||
|
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static ulong GetPlatformSeed(int seedInc)
|
||||||
|
{
|
||||||
|
ulong seed = (ulong)System.Diagnostics.Stopwatch.GetTimestamp();
|
||||||
|
return seed ^ ((ulong)Environment.WorkingSet + (ulong)seedInc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double Now { get { return (double)(Stopwatch.GetTimestamp() - s_timeInitialized) * s_dInvFreq; } }
|
||||||
|
|
||||||
|
private static NetworkInterface GetNetworkInterface()
|
||||||
|
{
|
||||||
|
var computerProperties = IPGlobalProperties.GetIPGlobalProperties();
|
||||||
|
if (computerProperties == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var nics = NetworkInterface.GetAllNetworkInterfaces();
|
||||||
|
if (nics == null || nics.Length < 1)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
NetworkInterface best = null;
|
||||||
|
foreach (NetworkInterface adapter in nics)
|
||||||
|
{
|
||||||
|
if (adapter.NetworkInterfaceType == NetworkInterfaceType.Loopback || adapter.NetworkInterfaceType == NetworkInterfaceType.Unknown)
|
||||||
|
continue;
|
||||||
|
if (!adapter.Supports(NetworkInterfaceComponent.IPv4))
|
||||||
|
continue;
|
||||||
|
if (best == null)
|
||||||
|
best = adapter;
|
||||||
|
if (adapter.OperationalStatus != OperationalStatus.Up)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// make sure this adapter has any ipv4 addresses
|
||||||
|
IPInterfaceProperties properties = adapter.GetIPProperties();
|
||||||
|
foreach (UnicastIPAddressInformation unicastAddress in properties.UnicastAddresses)
|
||||||
|
{
|
||||||
|
if (unicastAddress != null && unicastAddress.Address != null && unicastAddress.Address.AddressFamily == AddressFamily.InterNetwork)
|
||||||
|
{
|
||||||
|
// Yes it does, return this network interface.
|
||||||
|
return adapter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If available, returns the bytes of the physical (MAC) address for the first usable network interface
|
||||||
|
/// </summary>
|
||||||
|
public static byte[] GetMacAddressBytes()
|
||||||
|
{
|
||||||
|
var ni = GetNetworkInterface();
|
||||||
|
if (ni == null)
|
||||||
|
return null;
|
||||||
|
return ni.GetPhysicalAddress().GetAddressBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IPAddress GetBroadcastAddress()
|
||||||
|
{
|
||||||
|
var ni = GetNetworkInterface();
|
||||||
|
if (ni == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var properties = ni.GetIPProperties();
|
||||||
|
foreach (UnicastIPAddressInformation unicastAddress in properties.UnicastAddresses)
|
||||||
|
{
|
||||||
|
if (unicastAddress != null && unicastAddress.Address != null && unicastAddress.Address.AddressFamily == AddressFamily.InterNetwork)
|
||||||
|
{
|
||||||
|
var mask = unicastAddress.IPv4Mask;
|
||||||
|
byte[] ipAdressBytes = unicastAddress.Address.GetAddressBytes();
|
||||||
|
byte[] subnetMaskBytes = mask.GetAddressBytes();
|
||||||
|
|
||||||
|
if (ipAdressBytes.Length != subnetMaskBytes.Length)
|
||||||
|
throw new ArgumentException("Lengths of IP address and subnet mask do not match.");
|
||||||
|
|
||||||
|
byte[] broadcastAddress = new byte[ipAdressBytes.Length];
|
||||||
|
for (int i = 0; i < broadcastAddress.Length; i++)
|
||||||
|
{
|
||||||
|
broadcastAddress[i] = (byte)(ipAdressBytes[i] | (subnetMaskBytes[i] ^ 255));
|
||||||
|
}
|
||||||
|
return new IPAddress(broadcastAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return IPAddress.Broadcast;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets my local IPv4 address (not necessarily external) and subnet mask
|
||||||
|
/// </summary>
|
||||||
|
public static IPAddress GetMyAddress(out IPAddress mask)
|
||||||
|
{
|
||||||
|
var ni = GetNetworkInterface();
|
||||||
|
if (ni == null)
|
||||||
|
{
|
||||||
|
mask = null;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPInterfaceProperties properties = ni.GetIPProperties();
|
||||||
|
foreach (UnicastIPAddressInformation unicastAddress in properties.UnicastAddresses)
|
||||||
|
{
|
||||||
|
if (unicastAddress != null && unicastAddress.Address != null && unicastAddress.Address.AddressFamily == AddressFamily.InterNetwork)
|
||||||
|
{
|
||||||
|
mask = unicastAddress.IPv4Mask;
|
||||||
|
return unicastAddress.Address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mask = null;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Sleep(int milliseconds)
|
||||||
|
{
|
||||||
|
System.Threading.Thread.Sleep(milliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IPAddress CreateAddressFromBytes(byte[] bytes)
|
||||||
|
{
|
||||||
|
return new IPAddress(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly SHA256 s_sha = SHA256.Create();
|
||||||
|
public static byte[] ComputeSHAHash(byte[] bytes, int offset, int count)
|
||||||
|
{
|
||||||
|
return s_sha.ComputeHash(bytes, offset, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static partial class NetTime
|
||||||
|
{
|
||||||
|
private static readonly long s_timeInitialized = Stopwatch.GetTimestamp();
|
||||||
|
private static readonly double s_dInvFreq = 1.0 / (double)Stopwatch.Frequency;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get number of seconds since the application started
|
||||||
|
/// </summary>
|
||||||
|
public static double Now { get { return (double)(Stopwatch.GetTimestamp() - s_timeInitialized) * s_dInvFreq; } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
#if WINDOWS_RUNTIME
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Completely broken right now
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.NetworkInformation;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Lidgren.Network
|
||||||
|
{
|
||||||
|
public class NetAddress
|
||||||
|
{
|
||||||
|
public static readonly HostName Any = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NetEndPoint
|
||||||
|
{
|
||||||
|
public NetEndPoint(HostName hostname, int port) { HostName = hostname; Port = port; }
|
||||||
|
public NetEndPoint(HostName hostname, string port) { HostName = hostname; Port = int.Parse(port); }
|
||||||
|
public NetEndPoint(string hostname, int port) { HostName = (hostname == null) ? null : new HostName(hostname); Port = port; }
|
||||||
|
public HostName HostName;
|
||||||
|
public int Port;
|
||||||
|
public override string ToString() { return string.Format("{0}:{1}", HostName, Port); }
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return HostName.RawName.GetHashCode() + Port;
|
||||||
|
}
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
var ep = obj as NetEndPoint;
|
||||||
|
if (ep == null) return false;
|
||||||
|
if (Port != ep.Port) return false;
|
||||||
|
return HostName.RawName.Equals(ep.HostName.RawName);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static partial class NetUtility
|
||||||
|
{
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static ulong GetPlatformSeed(int seedInc)
|
||||||
|
{
|
||||||
|
ulong seed = (ulong)Environment.TickCount + (ulong)seedInc;
|
||||||
|
return seed ^ ((ulong)(new object().GetHashCode()) << 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the physical (MAC) address for the first usable network interface
|
||||||
|
/// </summary>
|
||||||
|
public static PhysicalAddress GetMacAddress()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IPAddress GetBroadcastAddress()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets my local IPv4 address (not necessarily external) and subnet mask
|
||||||
|
/// </summary>
|
||||||
|
public static IPAddress GetMyAddress(out IPAddress mask)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Sleep(int milliseconds)
|
||||||
|
{
|
||||||
|
Task.Delay(50).Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NetAddress CreateAddressFromBytes(byte[] bytes)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly SHA1CryptoServiceProvider s_sha = new SHA1CryptoServiceProvider();
|
||||||
|
public static byte[] ComputeSHAHash(byte[] bytes, int offset, int count)
|
||||||
|
{
|
||||||
|
return s_sha.ComputeHash(bytes, offset, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static partial class NetTime
|
||||||
|
{
|
||||||
|
private static readonly long s_timeInitialized = Environment.TickCount;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get number of seconds since the application started
|
||||||
|
/// </summary>
|
||||||
|
public static double Now { get { return (double)((uint)Environment.TickCount - s_timeInitialized) / 1000.0; } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Lidgren.Network
|
|
||||||
{
|
|
||||||
internal abstract class SenderChannelBase
|
|
||||||
{
|
|
||||||
internal abstract NetSendResult Send(float now, NetOutgoingMessage message);
|
|
||||||
internal abstract void SendQueuedMessages(float now);
|
|
||||||
internal abstract void Reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -99,6 +99,7 @@
|
|||||||
<Compile Include="Source\Map\LocationType.cs" />
|
<Compile Include="Source\Map\LocationType.cs" />
|
||||||
<Compile Include="Source\Map\SubmarineHull.cs" />
|
<Compile Include="Source\Map\SubmarineHull.cs" />
|
||||||
<Compile Include="Source\Networking\NetConfig.cs" />
|
<Compile Include="Source\Networking\NetConfig.cs" />
|
||||||
|
<Compile Include="Source\Networking\NetStats.cs" />
|
||||||
<Compile Include="Source\Particles\ParticleEmitter.cs" />
|
<Compile Include="Source\Particles\ParticleEmitter.cs" />
|
||||||
<Compile Include="Source\Screens\ServerListScreen.cs" />
|
<Compile Include="Source\Screens\ServerListScreen.cs" />
|
||||||
<Compile Include="Source\Utils\Rand.cs" />
|
<Compile Include="Source\Utils\Rand.cs" />
|
||||||
|
|||||||
@@ -61,7 +61,8 @@
|
|||||||
|
|
||||||
<Item
|
<Item
|
||||||
name="Railgun Shell"
|
name="Railgun Shell"
|
||||||
pickdistance="200">
|
pickdistance="200"
|
||||||
|
price="100">
|
||||||
|
|
||||||
<Sprite texture ="railgunshell.png" depth ="0.5"/>
|
<Sprite texture ="railgunshell.png" depth ="0.5"/>
|
||||||
|
|
||||||
|
|||||||
@@ -299,7 +299,7 @@ namespace Barotrauma
|
|||||||
//the collision is ignored if the lowest limb is under the platform
|
//the collision is ignored if the lowest limb is under the platform
|
||||||
if (lowestLimb==null || lowestLimb.Position.Y < structure.Rect.Y) return false;
|
if (lowestLimb==null || lowestLimb.Position.Y < structure.Rect.Y) return false;
|
||||||
}
|
}
|
||||||
else if (structure.StairDirection!=Direction.None)
|
else if (structure.StairDirection!=Direction.None && lowestLimb != null)
|
||||||
{
|
{
|
||||||
if (targetMovement.Y < 0.5f)
|
if (targetMovement.Y < 0.5f)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public bool Wrap;
|
public bool Wrap;
|
||||||
|
|
||||||
|
private float textDepth;
|
||||||
|
|
||||||
public override Vector4 Padding
|
public override Vector4 Padding
|
||||||
{
|
{
|
||||||
get { return padding; }
|
get { return padding; }
|
||||||
@@ -41,6 +43,12 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float TextDepth
|
||||||
|
{
|
||||||
|
get { return textDepth; }
|
||||||
|
set { textDepth = MathHelper.Clamp(value, 0.0f, 1.0f); }
|
||||||
|
}
|
||||||
|
|
||||||
public bool LimitText
|
public bool LimitText
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
@@ -221,7 +229,7 @@ namespace Barotrauma
|
|||||||
new Vector2(rect.X, rect.Y) + textPos,
|
new Vector2(rect.X, rect.Y) + textPos,
|
||||||
textColor * (textColor.A / 255.0f),
|
textColor * (textColor.A / 255.0f),
|
||||||
0.0f, origin, 1.0f,
|
0.0f, origin, 1.0f,
|
||||||
SpriteEffects.None, 0.0f);
|
SpriteEffects.None, textDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawChildren(spriteBatch);
|
DrawChildren(spriteBatch);
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ namespace Barotrauma
|
|||||||
Client traitor;
|
Client traitor;
|
||||||
Client target;
|
Client target;
|
||||||
|
|
||||||
|
private Character traitorCharacter, targetCharacter;
|
||||||
|
|
||||||
public TraitorMode(GameModePreset preset)
|
public TraitorMode(GameModePreset preset)
|
||||||
: base(preset)
|
: base(preset)
|
||||||
{
|
{
|
||||||
@@ -47,34 +49,38 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
target = GameMain.Server.connectedClients[targetIndex];
|
target = GameMain.Server.connectedClients[targetIndex];
|
||||||
|
|
||||||
|
traitorCharacter = traitor.character;
|
||||||
|
targetCharacter = target.character;
|
||||||
|
|
||||||
|
|
||||||
GameMain.Server.NewTraitor(traitor, target);
|
GameMain.Server.NewTraitor(traitor, target);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (target.character.IsDead)
|
if (target.character == null || target.character.IsDead)
|
||||||
{
|
{
|
||||||
string endMessage = traitor.character.Info.Name + " was a traitor! ";
|
string endMessage = traitorCharacter.Name + " was a traitor! ";
|
||||||
endMessage += (traitor.character.Info.Gender == Gender.Male) ? "His" : "Her";
|
endMessage += (traitorCharacter.Info.Gender == Gender.Male) ? "His" : "Her";
|
||||||
endMessage += " task was to assassinate " + target.character.Info.Name + ". The task was successful.";
|
endMessage += " task was to assassinate " + targetCharacter.Name + ". The task was successful.";
|
||||||
End(endMessage);
|
End(endMessage);
|
||||||
}
|
}
|
||||||
else if (traitor.character.IsDead)
|
else if (traitor.character == null || traitor.character.IsDead)
|
||||||
{
|
{
|
||||||
string endMessage = traitor.character.Info.Name + " was a traitor! ";
|
string endMessage = traitorCharacter.Name + " was a traitor! ";
|
||||||
endMessage += (traitor.character.Info.Gender == Gender.Male) ? "His" : "Her";
|
//TODO: remove references to traitor.character
|
||||||
endMessage += " task was to assassinate " + target.character.Info.Name + ", but ";
|
endMessage += (traitorCharacter.Info.Gender == Gender.Male) ? "His" : "Her";
|
||||||
endMessage += (traitor.character.Info.Gender == Gender.Male) ? "he" : "she";
|
endMessage += " task was to assassinate " + targetCharacter.Name + ", but ";
|
||||||
endMessage += " got " + ((traitor.character.Info.Gender == Gender.Male) ? "himself" : "herself");
|
endMessage += (traitorCharacter.Info.Gender == Gender.Male) ? "he" : "she";
|
||||||
|
endMessage += " got " + ((traitorCharacter.Info.Gender == Gender.Male) ? "himself" : "herself");
|
||||||
endMessage += " killed before completing it.";
|
endMessage += " killed before completing it.";
|
||||||
End(endMessage);
|
End(endMessage);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (Level.Loaded.AtEndPosition)
|
else if (Level.Loaded.AtEndPosition)
|
||||||
{
|
{
|
||||||
string endMessage = traitor.character.Info.Name + " was a traitor! ";
|
string endMessage = traitorCharacter.Name + " was a traitor! ";
|
||||||
endMessage += (traitor.character.Info.Gender == Gender.Male) ? "His" : "Her";
|
endMessage += (traitorCharacter.Info.Gender == Gender.Male) ? "His" : "Her";
|
||||||
endMessage += " task was to assassinate " + target.character.Info.Name + ". ";
|
endMessage += " task was to assassinate " + targetCharacter.Name + ". ";
|
||||||
endMessage += "The task was unsuccessful - the has submarine reached its destination.";
|
endMessage += "The task was unsuccessful - the has submarine reached its destination.";
|
||||||
End(endMessage);
|
End(endMessage);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
GameMain.GameSession = new GameSession(Submarine.Loaded, "", GameModePreset.list.Find(gm => gm.Name.ToLower()=="tutorial"));
|
GameMain.GameSession = new GameSession(Submarine.Loaded, "", GameModePreset.list.Find(gm => gm.Name.ToLower()=="tutorial"));
|
||||||
|
|
||||||
GameMain.GameSession.StartShift("tutorial");
|
GameMain.GameSession.StartShift("tuto");
|
||||||
|
|
||||||
GameMain.GameSession.taskManager.Tasks.Clear();
|
GameMain.GameSession.taskManager.Tasks.Clear();
|
||||||
|
|
||||||
@@ -164,6 +164,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
while (Math.Abs(reactor.Temperature-3000.0f) > 100.0f)
|
while (Math.Abs(reactor.Temperature-3000.0f) > 100.0f)
|
||||||
{
|
{
|
||||||
|
reactor.AutoTemp = false;
|
||||||
reactor.ShutDownTemp = Math.Min(reactor.ShutDownTemp, 5000.0f);
|
reactor.ShutDownTemp = Math.Min(reactor.ShutDownTemp, 5000.0f);
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,6 +131,18 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
picker = character;
|
picker = character;
|
||||||
|
|
||||||
|
if (item.body == null)
|
||||||
|
{
|
||||||
|
if (body!=null)
|
||||||
|
{
|
||||||
|
item.body = body;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!item.body.Enabled)
|
if (!item.body.Enabled)
|
||||||
{
|
{
|
||||||
Limb rightHand = picker.AnimController.GetLimb(LimbType.RightHand);
|
Limb rightHand = picker.AnimController.GetLimb(LimbType.RightHand);
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ namespace Barotrauma.Items.Components
|
|||||||
null, null, true);
|
null, null, true);
|
||||||
textBlock.Font = GUI.SmallFont;
|
textBlock.Font = GUI.SmallFont;
|
||||||
textBlock.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f);
|
textBlock.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f);
|
||||||
|
textBlock.TextDepth = item.Sprite.Depth - 0.0001f;
|
||||||
}
|
}
|
||||||
return textBlock;
|
return textBlock;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,7 +103,11 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
if (stickJoint != null && doesStick)
|
if (stickJoint != null && doesStick)
|
||||||
{
|
{
|
||||||
if (stickTarget!=null) item.body.FarseerBody.RestoreCollisionWith(stickTarget);
|
if (stickTarget != null)
|
||||||
|
{
|
||||||
|
item.body.FarseerBody.RestoreCollisionWith(stickTarget);
|
||||||
|
stickTarget = null;
|
||||||
|
}
|
||||||
GameMain.World.RemoveJoint(stickJoint);
|
GameMain.World.RemoveJoint(stickJoint);
|
||||||
stickJoint = null;
|
stickJoint = null;
|
||||||
}
|
}
|
||||||
@@ -111,25 +115,19 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
public override void Update(float deltaTime, Camera cam)
|
public override void Update(float deltaTime, Camera cam)
|
||||||
{
|
{
|
||||||
if (stickJoint != null)
|
if (stickJoint != null && stickJoint.JointTranslation < 0.01f)
|
||||||
{
|
{
|
||||||
if (stickJoint.JointTranslation < 0.01f)
|
if (stickTarget!=null)
|
||||||
{
|
{
|
||||||
if (stickTarget!=null)
|
item.body.FarseerBody.RestoreCollisionWith(stickTarget);
|
||||||
{
|
stickTarget = null;
|
||||||
item.body.FarseerBody.RestoreCollisionWith(stickTarget);
|
|
||||||
}
|
|
||||||
|
|
||||||
GameMain.World.RemoveJoint(stickJoint);
|
|
||||||
stickJoint = null;
|
|
||||||
|
|
||||||
IsActive = false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
GameMain.World.RemoveJoint(stickJoint);
|
||||||
{
|
stickJoint = null;
|
||||||
IsActive = false;
|
|
||||||
}
|
IsActive = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool OnProjectileCollision(Fixture f1, Fixture f2, Contact contact)
|
private bool OnProjectileCollision(Fixture f1, Fixture f2, Contact contact)
|
||||||
|
|||||||
@@ -230,6 +230,13 @@ namespace Barotrauma
|
|||||||
int itemCapacity = item.Capacity;
|
int itemCapacity = item.Capacity;
|
||||||
if (itemCapacity == 0) return;
|
if (itemCapacity == 0) return;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
System.Diagnostics.Debug.Assert(slotIndex>=0 && slotIndex<items.Length);
|
||||||
|
#else
|
||||||
|
if (slotIndex<0 || slotIndex>=items.Length) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
Rectangle containerRect = new Rectangle(rect.X - 5, rect.Y - (rect.Height + 10) * itemCapacity - 5,
|
Rectangle containerRect = new Rectangle(rect.X - 5, rect.Y - (rect.Height + 10) * itemCapacity - 5,
|
||||||
rect.Width + 10, rect.Height + (rect.Height + 10) * itemCapacity + 10);
|
rect.Width + 10, rect.Height + (rect.Height + 10) * itemCapacity + 10);
|
||||||
|
|
||||||
@@ -253,6 +260,7 @@ namespace Barotrauma
|
|||||||
protected void DrawSlot(SpriteBatch spriteBatch, Rectangle rect, Item item, bool isHighLighted, bool isSubSlot)
|
protected void DrawSlot(SpriteBatch spriteBatch, Rectangle rect, Item item, bool isHighLighted, bool isSubSlot)
|
||||||
{
|
{
|
||||||
GUI.DrawRectangle(spriteBatch, rect, (isHighLighted ? Color.Red : Color.White) * ((isSubSlot) ? 0.1f : 0.3f), true);
|
GUI.DrawRectangle(spriteBatch, rect, (isHighLighted ? Color.Red : Color.White) * ((isSubSlot) ? 0.1f : 0.3f), true);
|
||||||
|
GUI.DrawRectangle(spriteBatch, rect, (isHighLighted ? Color.Red : Color.White) * ((isSubSlot) ? 0.2f : 0.4f), false);
|
||||||
|
|
||||||
if (item == null) return;
|
if (item == null) return;
|
||||||
|
|
||||||
|
|||||||
@@ -1163,11 +1163,19 @@ namespace Barotrauma
|
|||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case NetworkEventType.DropItem:
|
case NetworkEventType.DropItem:
|
||||||
if (body != null) body.FillNetworkData(type, message);
|
if (body != null)
|
||||||
|
{
|
||||||
|
message.Write(body.SimPosition.X);
|
||||||
|
message.Write(body.SimPosition.Y);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case NetworkEventType.UpdateComponent:
|
case NetworkEventType.UpdateComponent:
|
||||||
message.Write((int)data);
|
|
||||||
components[(int)data].FillNetworkData(type, message);
|
int componentIndex = (int)data;
|
||||||
|
if (componentIndex < 0 || componentIndex >= components.Count) return;
|
||||||
|
|
||||||
|
message.Write((byte)componentIndex);
|
||||||
|
components[componentIndex].FillNetworkData(type, message);
|
||||||
break;
|
break;
|
||||||
case NetworkEventType.UpdateProperty:
|
case NetworkEventType.UpdateProperty:
|
||||||
var allProperties = GetProperties<InGameEditable>();
|
var allProperties = GetProperties<InGameEditable>();
|
||||||
@@ -1215,11 +1223,16 @@ namespace Barotrauma
|
|||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case NetworkEventType.DropItem:
|
case NetworkEventType.DropItem:
|
||||||
if (body != null) body.ReadNetworkData(type, message);
|
Vector2 newSimPos = Vector2.Zero;
|
||||||
|
if (body != null)
|
||||||
|
{
|
||||||
|
newSimPos = new Vector2(message.ReadFloat(), message.ReadFloat());
|
||||||
|
}
|
||||||
|
SetTransform(newSimPos, body.Rotation);
|
||||||
Drop(null, false);
|
Drop(null, false);
|
||||||
break;
|
break;
|
||||||
case NetworkEventType.UpdateComponent:
|
case NetworkEventType.UpdateComponent:
|
||||||
int componentIndex = message.ReadInt32();
|
int componentIndex = message.ReadByte();
|
||||||
if (componentIndex < 0 || componentIndex > components.Count - 1) return;
|
if (componentIndex < 0 || componentIndex > components.Count - 1) return;
|
||||||
components[componentIndex].ReadNetworkData(type, message);
|
components[componentIndex].ReadNetworkData(type, message);
|
||||||
break;
|
break;
|
||||||
@@ -1272,7 +1285,7 @@ namespace Barotrauma
|
|||||||
base.Remove();
|
base.Remove();
|
||||||
|
|
||||||
//sprite.Remove();
|
//sprite.Remove();
|
||||||
if (body != null) body.Remove();
|
//if (body != null) body.Remove();
|
||||||
|
|
||||||
foreach (ItemComponent ic in components)
|
foreach (ItemComponent ic in components)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -255,7 +255,15 @@ namespace Barotrauma
|
|||||||
assignedWayPoints[i] = GetRandom(SpawnType.Human);
|
assignedWayPoints[i] = GetRandom(SpawnType.Human);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < assignedWayPoints.Length; i++ )
|
||||||
|
{
|
||||||
|
if (assignedWayPoints[i]==null)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Couldn't find a waypoint for " + crew[i].Name + "!");
|
||||||
|
assignedWayPoints[i] = WayPointList[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return assignedWayPoints;
|
return assignedWayPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ namespace Barotrauma.Networking
|
|||||||
NetConnectionStatus connectionStatus = (NetConnectionStatus)inc.ReadByte();
|
NetConnectionStatus connectionStatus = (NetConnectionStatus)inc.ReadByte();
|
||||||
Debug.WriteLine(connectionStatus);
|
Debug.WriteLine(connectionStatus);
|
||||||
|
|
||||||
if (connectionStatus != NetConnectionStatus.Connected)
|
if (connectionStatus == NetConnectionStatus.Disconnected)
|
||||||
{
|
{
|
||||||
string denyMessage = inc.ReadString();
|
string denyMessage = inc.ReadString();
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ namespace Barotrauma.Networking
|
|||||||
//for keeping track of disconnected clients in case the reconnect shortly after
|
//for keeping track of disconnected clients in case the reconnect shortly after
|
||||||
private List<Client> disconnectedClients = new List<Client>();
|
private List<Client> disconnectedClients = new List<Client>();
|
||||||
|
|
||||||
|
private NetStats netStats;
|
||||||
|
|
||||||
//is the server running
|
//is the server running
|
||||||
bool started;
|
bool started;
|
||||||
|
|
||||||
@@ -34,6 +36,20 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
private string password;
|
private string password;
|
||||||
|
|
||||||
|
private bool autoRestart;
|
||||||
|
|
||||||
|
public bool AutoRestart
|
||||||
|
{
|
||||||
|
get { return (connectedClients.Count==0) ? false : autoRestart; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
autoRestart = value;
|
||||||
|
|
||||||
|
AutoRestartTimer = autoRestart ? 20.0f : 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public float AutoRestartTimer;
|
||||||
|
|
||||||
public GameServer(string name, int port, bool isPublic = false, string password = "", bool attemptUPnP = false, int maxPlayers = 10)
|
public GameServer(string name, int port, bool isPublic = false, string password = "", bool attemptUPnP = false, int maxPlayers = 10)
|
||||||
{
|
{
|
||||||
var endRoundButton = new GUIButton(new Rectangle(GameMain.GraphicsWidth - 290, 20, 150, 25), "End round", Alignment.TopLeft, GUI.Style, inGameHUD);
|
var endRoundButton = new GUIButton(new Rectangle(GameMain.GraphicsWidth - 290, 20, 150, 25), "End round", Alignment.TopLeft, GUI.Style, inGameHUD);
|
||||||
@@ -44,9 +60,13 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
config = new NetPeerConfiguration("barotrauma");
|
config = new NetPeerConfiguration("barotrauma");
|
||||||
|
|
||||||
|
netStats = new NetStats();
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
config.SimulatedLoss = 0.2f;
|
config.SimulatedLoss = 0.2f;
|
||||||
config.SimulatedMinimumLatency = 0.3f;
|
config.SimulatedMinimumLatency = 0.3f;
|
||||||
|
config.SimulatedDuplicatesChance = 0.05f;
|
||||||
|
config.SimulatedMinimumLatency = 0.1f;
|
||||||
#endif
|
#endif
|
||||||
config.Port = port;
|
config.Port = port;
|
||||||
Port = port;
|
Port = port;
|
||||||
@@ -61,9 +81,9 @@ namespace Barotrauma.Networking
|
|||||||
config.DisableMessageType(NetIncomingMessageType.DebugMessage |
|
config.DisableMessageType(NetIncomingMessageType.DebugMessage |
|
||||||
NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt |
|
NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt |
|
||||||
NetIncomingMessageType.ErrorMessage | NetIncomingMessageType.Error);
|
NetIncomingMessageType.ErrorMessage | NetIncomingMessageType.Error);
|
||||||
|
|
||||||
config.EnableMessageType(NetIncomingMessageType.ConnectionApproval);
|
config.EnableMessageType(NetIncomingMessageType.ConnectionApproval);
|
||||||
|
|
||||||
CoroutineManager.StartCoroutine(StartServer(isPublic));
|
CoroutineManager.StartCoroutine(StartServer(isPublic));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,21 +210,23 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
if (response.ErrorException != null)
|
if (response.ErrorException != null)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("Error while connecting to master server", response.ErrorException);
|
DebugConsole.ThrowError("Error while registering to master server", response.ErrorException);
|
||||||
registeredToMaster = false;
|
registeredToMaster = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.StatusCode != System.Net.HttpStatusCode.OK)
|
if (response.StatusCode != System.Net.HttpStatusCode.OK)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("Error while connecting to master server (" + response.StatusCode + ": " + response.StatusDescription + ")");
|
DebugConsole.NewMessage("Error while reporting to master server (" + response.StatusCode + ": " + response.StatusDescription + ")", Color.Red);
|
||||||
registeredToMaster = false;
|
//registeredToMaster = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(float deltaTime)
|
public override void Update(float deltaTime)
|
||||||
{
|
{
|
||||||
|
if (GameMain.DebugDraw) netStats.Update(deltaTime);
|
||||||
|
|
||||||
if (!started) return;
|
if (!started) return;
|
||||||
|
|
||||||
base.Update(deltaTime);
|
base.Update(deltaTime);
|
||||||
@@ -212,6 +234,24 @@ namespace Barotrauma.Networking
|
|||||||
if (gameStarted)
|
if (gameStarted)
|
||||||
{
|
{
|
||||||
inGameHUD.Update((float)Physics.step);
|
inGameHUD.Update((float)Physics.step);
|
||||||
|
|
||||||
|
//if all characters dead
|
||||||
|
if (AutoRestart &&
|
||||||
|
connectedClients.Find(c => c.character != null && !c.character.IsDead)==null &&
|
||||||
|
(myCharacter == null || myCharacter.IsDead))
|
||||||
|
{
|
||||||
|
EndButtonHit(null, null);
|
||||||
|
AutoRestartTimer = 20.0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (autoRestart && Screen.Selected == GameMain.NetLobbyScreen && connectedClients.Count>0)
|
||||||
|
{
|
||||||
|
AutoRestartTimer -= deltaTime;
|
||||||
|
if (AutoRestartTimer < 0.0f)
|
||||||
|
{
|
||||||
|
StartGameClicked(null,null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = disconnectedClients.Count - 1; i >= 0; i-- )
|
for (int i = disconnectedClients.Count - 1; i >= 0; i-- )
|
||||||
@@ -628,7 +668,7 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
List<Character> crew = new List<Character>();
|
List<Character> crew = new List<Character>();
|
||||||
WayPoint[] assignedWayPoints = WayPoint.SelectCrewSpawnPoints(characterInfos);
|
WayPoint[] assignedWayPoints = WayPoint.SelectCrewSpawnPoints(characterInfos);
|
||||||
|
|
||||||
for (int i = 0; i < connectedClients.Count; i++)
|
for (int i = 0; i < connectedClients.Count; i++)
|
||||||
{
|
{
|
||||||
connectedClients[i].character = new Character(
|
connectedClients[i].character = new Character(
|
||||||
@@ -817,7 +857,7 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
public void NewTraitor(Client traitor, Client target)
|
public void NewTraitor(Client traitor, Client target)
|
||||||
{
|
{
|
||||||
new GUIMessageBox("New traitor", traitor.name + " is the traitor and the target is " + target.name+".");
|
//new GUIMessageBox("New traitor", traitor.name + " is the traitor and the target is " + target.name+".");
|
||||||
|
|
||||||
NetOutgoingMessage msg = server.CreateMessage();
|
NetOutgoingMessage msg = server.CreateMessage();
|
||||||
msg.Write((byte)PacketTypes.Traitor);
|
msg.Write((byte)PacketTypes.Traitor);
|
||||||
@@ -846,15 +886,27 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
spriteBatch.DrawString(GUI.SmallFont, "Sent bytes: " + server.Statistics.SentBytes, new Vector2(x + 10, y + 75), Color.White);
|
spriteBatch.DrawString(GUI.SmallFont, "Sent bytes: " + server.Statistics.SentBytes, new Vector2(x + 10, y + 75), Color.White);
|
||||||
spriteBatch.DrawString(GUI.SmallFont, "Sent packets: " + server.Statistics.SentPackets, new Vector2(x + 10, y + 90), Color.White);
|
spriteBatch.DrawString(GUI.SmallFont, "Sent packets: " + server.Statistics.SentPackets, new Vector2(x + 10, y + 90), Color.White);
|
||||||
|
|
||||||
|
int resentMessages = 0;
|
||||||
|
|
||||||
y += 110;
|
y += 110;
|
||||||
foreach (Client c in connectedClients)
|
foreach (Client c in connectedClients)
|
||||||
{
|
{
|
||||||
spriteBatch.DrawString(GUI.SmallFont, c.name + ":", new Vector2(x + 10, y), Color.White);
|
spriteBatch.DrawString(GUI.SmallFont, c.name + ":", new Vector2(x + 10, y), Color.White);
|
||||||
spriteBatch.DrawString(GUI.SmallFont, "- avg roundtrip " + c.Connection.AverageRoundtripTime+" s", new Vector2(x + 20, y + 15), Color.White);
|
spriteBatch.DrawString(GUI.SmallFont, "- avg roundtrip " + c.Connection.AverageRoundtripTime+" s", new Vector2(x + 20, y + 15), Color.White);
|
||||||
y += 50;
|
spriteBatch.DrawString(GUI.SmallFont, "- resent messages " + c.Connection.Statistics.ResentMessages, new Vector2(x + 20, y + 30), Color.White);
|
||||||
|
|
||||||
|
resentMessages += (int)c.Connection.Statistics.ResentMessages;
|
||||||
|
|
||||||
|
y += 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netStats.AddValue(NetStats.NetStatType.ResentMessages, resentMessages);
|
||||||
|
netStats.AddValue(NetStats.NetStatType.SentBytes, server.Statistics.SentBytes);
|
||||||
|
netStats.AddValue(NetStats.NetStatType.ReceivedBytes, server.Statistics.ReceivedBytes);
|
||||||
|
|
||||||
|
netStats.Draw(spriteBatch, new Rectangle(200,0,800,200));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool UpdateNetLobby(object obj)
|
public bool UpdateNetLobby(object obj)
|
||||||
|
|||||||
@@ -0,0 +1,163 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Barotrauma.Networking
|
||||||
|
{
|
||||||
|
class NetStats
|
||||||
|
{
|
||||||
|
public enum NetStatType
|
||||||
|
{
|
||||||
|
SentBytes = 0,
|
||||||
|
ReceivedBytes = 1,
|
||||||
|
ResentMessages = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
private Graph[] graphs;
|
||||||
|
|
||||||
|
private Queue<float>[] valueQueue;
|
||||||
|
|
||||||
|
private float[] lastValues;
|
||||||
|
|
||||||
|
const float UpdateInterval = 1.0f;
|
||||||
|
float updateTimer;
|
||||||
|
|
||||||
|
public NetStats()
|
||||||
|
{
|
||||||
|
graphs = new Graph[3];
|
||||||
|
|
||||||
|
valueQueue = new Queue<float>[3];
|
||||||
|
for (int i = 0; i < 3; i++ )
|
||||||
|
{
|
||||||
|
valueQueue[i] = new Queue<float>();
|
||||||
|
graphs[i] = new Graph();
|
||||||
|
}
|
||||||
|
|
||||||
|
lastValues = new float[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddValue(NetStatType statType, float value)
|
||||||
|
{
|
||||||
|
float valueChange = value - lastValues[(int)statType];
|
||||||
|
|
||||||
|
valueQueue[(int)statType].Enqueue(valueChange);
|
||||||
|
|
||||||
|
lastValues[(int)statType] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(float deltaTime)
|
||||||
|
{
|
||||||
|
updateTimer -= deltaTime;
|
||||||
|
|
||||||
|
if (updateTimer > 0.0f) return;
|
||||||
|
|
||||||
|
for (int i = 0; i<3; i++)
|
||||||
|
{
|
||||||
|
int valueCount = valueQueue[i].Count;
|
||||||
|
float totalValue = 0.0f;
|
||||||
|
while (valueQueue[i].Count>1)
|
||||||
|
{
|
||||||
|
totalValue += valueQueue[i].Dequeue();
|
||||||
|
}
|
||||||
|
|
||||||
|
graphs[i].Update(valueCount==0 ? 0.0f : totalValue/valueCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTimer = UpdateInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(SpriteBatch spriteBatch, Rectangle rect)
|
||||||
|
{
|
||||||
|
GUI.DrawRectangle(spriteBatch, rect, Color.Black*0.4f, true);
|
||||||
|
|
||||||
|
graphs[(int)NetStatType.ReceivedBytes].Draw(spriteBatch, rect, null, 0.0f, Color.Cyan);
|
||||||
|
|
||||||
|
graphs[(int)NetStatType.SentBytes].Draw(spriteBatch, rect, null, 0.0f, Color.Orange);
|
||||||
|
|
||||||
|
graphs[(int)NetStatType.ResentMessages].Draw(spriteBatch, rect, null, 0.0f, Color.Red);
|
||||||
|
|
||||||
|
spriteBatch.DrawString(GUI.SmallFont, "Max received: "+graphs[(int)NetStatType.ReceivedBytes].LargestValue()+" bytes/s",
|
||||||
|
new Vector2(rect.X + 10, rect.Y+10), Color.Cyan);
|
||||||
|
|
||||||
|
spriteBatch.DrawString(GUI.SmallFont, "Max sent: " + graphs[(int)NetStatType.SentBytes].LargestValue() + " bytes/s",
|
||||||
|
new Vector2(rect.X + 10, rect.Y + 30), Color.Orange);
|
||||||
|
|
||||||
|
spriteBatch.DrawString(GUI.SmallFont, "Max resent: " + graphs[(int)NetStatType.ResentMessages].LargestValue() + " messages/s",
|
||||||
|
new Vector2(rect.X + 10, rect.Y + 50), Color.Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Graph
|
||||||
|
{
|
||||||
|
const int ArraySize = 100;
|
||||||
|
|
||||||
|
private float[] values;
|
||||||
|
|
||||||
|
public Graph()
|
||||||
|
{
|
||||||
|
values = new float[ArraySize];
|
||||||
|
}
|
||||||
|
|
||||||
|
public float LargestValue()
|
||||||
|
{
|
||||||
|
float maxValue = 0.0f;
|
||||||
|
for (int i = 0; i < values.Length; i++)
|
||||||
|
{
|
||||||
|
if (values[i] > maxValue) maxValue = values[i];
|
||||||
|
}
|
||||||
|
return maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(float newValue)
|
||||||
|
{
|
||||||
|
for (int i = values.Length-1; i > 0; i--)
|
||||||
|
{
|
||||||
|
values[i] = values[i - 1];
|
||||||
|
}
|
||||||
|
values[0] = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(SpriteBatch spriteBatch, Rectangle rect, float? maxVal, float xOffset, Color color)
|
||||||
|
{
|
||||||
|
float graphMaxVal = 1.0f;
|
||||||
|
if (maxVal == null)
|
||||||
|
{
|
||||||
|
graphMaxVal = LargestValue();
|
||||||
|
}
|
||||||
|
else if (maxVal > 0.0f)
|
||||||
|
{
|
||||||
|
graphMaxVal = (float)maxVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
float lineWidth = (float)rect.Width / (float)(values.Length - 2);
|
||||||
|
float yScale = (float)rect.Height / graphMaxVal;
|
||||||
|
|
||||||
|
GUI.DrawRectangle(spriteBatch, rect, Color.White);
|
||||||
|
|
||||||
|
Vector2 prevPoint = new Vector2(rect.Right, rect.Bottom - (values[1] + (values[0] - values[1]) * xOffset) * yScale);
|
||||||
|
|
||||||
|
float currX = rect.Right - ((xOffset - 1.0f) * lineWidth);
|
||||||
|
|
||||||
|
for (int i = 1; i < values.Length - 1; i++)
|
||||||
|
{
|
||||||
|
currX -= lineWidth;
|
||||||
|
|
||||||
|
Vector2 newPoint = new Vector2(currX, rect.Bottom - values[i] * yScale);
|
||||||
|
|
||||||
|
GUI.DrawLine(spriteBatch, prevPoint, newPoint - new Vector2(1.0f, 0), color);
|
||||||
|
|
||||||
|
prevPoint = newPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 lastPoint = new Vector2(rect.X,
|
||||||
|
rect.Bottom - (values[values.Length - 1] + (values[values.Length - 2] - values[values.Length - 1]) * xOffset) * yScale);
|
||||||
|
|
||||||
|
GUI.DrawLine(spriteBatch, prevPoint, lastPoint, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -124,8 +124,15 @@ namespace Barotrauma.Networking
|
|||||||
System.Diagnostics.Debug.WriteLine("Networkevent entity: "+e.ToString());
|
System.Diagnostics.Debug.WriteLine("Networkevent entity: "+e.ToString());
|
||||||
|
|
||||||
//System.Diagnostics.Debug.WriteLine("new message: " + eventType +" - "+e);
|
//System.Diagnostics.Debug.WriteLine("new message: " + eventType +" - "+e);
|
||||||
|
try
|
||||||
e.ReadNetworkData(eventType, message);
|
{
|
||||||
|
e.ReadNetworkData(eventType, message);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Received invalid network message");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,19 +28,19 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
using (var game = new GameMain())
|
using (var game = new GameMain())
|
||||||
{
|
{
|
||||||
//#if !DEBUG
|
#if !DEBUG
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//#endif
|
#endif
|
||||||
|
|
||||||
game.Run();
|
game.Run();
|
||||||
//#if !DEBUG
|
#if !DEBUG
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
CrashDump(game, "crashreport.txt", e);
|
CrashDump(game, "crashreport.txt", e);
|
||||||
}
|
}
|
||||||
//#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace Barotrauma
|
|||||||
private GUIListBox playerList;
|
private GUIListBox playerList;
|
||||||
|
|
||||||
private GUIListBox subList, modeList, chatBox;
|
private GUIListBox subList, modeList, chatBox;
|
||||||
|
|
||||||
private GUIListBox jobList;
|
private GUIListBox jobList;
|
||||||
|
|
||||||
private GUITextBox textBox, seedBox;
|
private GUITextBox textBox, seedBox;
|
||||||
@@ -29,6 +29,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private GUIFrame playerFrame;
|
private GUIFrame playerFrame;
|
||||||
|
|
||||||
|
private GUITickBox autoRestartBox;
|
||||||
|
|
||||||
private float camAngle;
|
private float camAngle;
|
||||||
|
|
||||||
public bool IsServer;
|
public bool IsServer;
|
||||||
@@ -91,10 +93,18 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//public string DurationText()
|
private float autoRestartTimer;
|
||||||
//{
|
|
||||||
// return "Duration: " + GameDuration.TotalMinutes + " min";
|
public string AutoRestartText()
|
||||||
//}
|
{
|
||||||
|
if (GameMain.Server != null)
|
||||||
|
{
|
||||||
|
if (!GameMain.Server.AutoRestart) return "";
|
||||||
|
return "Restarting in " + (int)GameMain.Server.AutoRestartTimer;
|
||||||
|
}
|
||||||
|
if (autoRestartTimer == 0.0f) return "";
|
||||||
|
return "Restarting in " + (int)autoRestartTimer;
|
||||||
|
}
|
||||||
|
|
||||||
public NetLobbyScreen()
|
public NetLobbyScreen()
|
||||||
{
|
{
|
||||||
@@ -194,7 +204,6 @@ namespace Barotrauma
|
|||||||
|
|
||||||
//gamemode description ------------------------------------------------------------------
|
//gamemode description ------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
var modeDescription = new GUITextBlock(
|
var modeDescription = new GUITextBlock(
|
||||||
new Rectangle(columnX, 150, (int)(columnWidth * 1.5f), infoFrame.Rect.Height - 150 - 80),
|
new Rectangle(columnX, 150, (int)(columnWidth * 1.5f), infoFrame.Rect.Height - 150 - 80),
|
||||||
"", GUI.Style, Alignment.TopLeft, Alignment.TopLeft, infoFrame, true, GameMain.GraphicsWidth>1024 ? GUI.Font : GUI.SmallFont);
|
"", GUI.Style, Alignment.TopLeft, Alignment.TopLeft, infoFrame, true, GameMain.GraphicsWidth>1024 ? GUI.Font : GUI.SmallFont);
|
||||||
@@ -214,6 +223,14 @@ namespace Barotrauma
|
|||||||
seedBox.OnTextChanged = SelectSeed;
|
seedBox.OnTextChanged = SelectSeed;
|
||||||
LevelSeed = ToolBox.RandomSeed(8);
|
LevelSeed = ToolBox.RandomSeed(8);
|
||||||
|
|
||||||
|
//automatic restart ------------------------------------------------------------------
|
||||||
|
|
||||||
|
autoRestartBox = new GUITickBox(new Rectangle(columnX, 190, 20, 20), "Automatic restart", Alignment.TopLeft, infoFrame);
|
||||||
|
autoRestartBox.OnSelected = ToggleAutoRestart;
|
||||||
|
|
||||||
|
var restartText = new GUITextBlock(new Rectangle(columnX, 210, 20, 20), "", GUI.Style, infoFrame);
|
||||||
|
restartText.TextGetter = AutoRestartText;
|
||||||
|
|
||||||
//server info ------------------------------------------------------------------
|
//server info ------------------------------------------------------------------
|
||||||
|
|
||||||
var serverName = new GUITextBox(new Rectangle(0, 0, 200, 20), null, null, Alignment.TopLeft, Alignment.TopLeft, GUI.Style, infoFrame);
|
var serverName = new GUITextBox(new Rectangle(0, 0, 200, 20), null, null, Alignment.TopLeft, Alignment.TopLeft, GUI.Style, infoFrame);
|
||||||
@@ -230,6 +247,8 @@ namespace Barotrauma
|
|||||||
public override void Deselect()
|
public override void Deselect()
|
||||||
{
|
{
|
||||||
textBox.Deselect();
|
textBox.Deselect();
|
||||||
|
|
||||||
|
seedBox.Text = ToolBox.RandomSeed(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Select()
|
public override void Select()
|
||||||
@@ -372,6 +391,20 @@ namespace Barotrauma
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool ToggleAutoRestart(object obj)
|
||||||
|
{
|
||||||
|
if (GameMain.Server == null) return false;
|
||||||
|
|
||||||
|
GUITickBox tickBox = obj as GUITickBox;
|
||||||
|
if (tickBox==null) return false;
|
||||||
|
|
||||||
|
GameMain.Server.AutoRestart = tickBox.Selected;
|
||||||
|
|
||||||
|
GameMain.Server.UpdateNetLobby(obj);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private bool SelectMap(GUIComponent component, object obj)
|
private bool SelectMap(GUIComponent component, object obj)
|
||||||
{
|
{
|
||||||
if (GameMain.Server != null) GameMain.Server.UpdateNetLobby(obj);
|
if (GameMain.Server != null) GameMain.Server.UpdateNetLobby(obj);
|
||||||
@@ -491,6 +524,11 @@ namespace Barotrauma
|
|||||||
if (jobInfoFrame != null) jobInfoFrame.Update((float)deltaTime);
|
if (jobInfoFrame != null) jobInfoFrame.Update((float)deltaTime);
|
||||||
|
|
||||||
if (playerFrame != null) playerFrame.Update((float)deltaTime);
|
if (playerFrame != null) playerFrame.Update((float)deltaTime);
|
||||||
|
|
||||||
|
if (autoRestartTimer != 0.0f && autoRestartBox.Selected)
|
||||||
|
{
|
||||||
|
autoRestartTimer = Math.Max(autoRestartTimer - (float)deltaTime, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
//durationBar.BarScroll = Math.Max(durationBar.BarScroll, 1.0f / 60.0f);
|
//durationBar.BarScroll = Math.Max(durationBar.BarScroll, 1.0f / 60.0f);
|
||||||
}
|
}
|
||||||
@@ -722,13 +760,15 @@ namespace Barotrauma
|
|||||||
//msg.Write(durationBar.BarScroll);
|
//msg.Write(durationBar.BarScroll);
|
||||||
msg.Write(LevelSeed);
|
msg.Write(LevelSeed);
|
||||||
|
|
||||||
|
msg.Write(GameMain.Server==null ? false : GameMain.Server.AutoRestart);
|
||||||
|
msg.Write(GameMain.Server == null ? 0.0f : GameMain.Server.AutoRestartTimer);
|
||||||
|
|
||||||
msg.Write((byte)(playerList.CountChildren));
|
msg.Write((byte)(playerList.CountChildren));
|
||||||
for (int i = 0; i < playerList.CountChildren; i++)
|
for (int i = 0; i < playerList.CountChildren; i++)
|
||||||
{
|
{
|
||||||
string clientName = playerList.children[i].UserData as string;
|
string clientName = playerList.children[i].UserData as string;
|
||||||
msg.Write(clientName==null ? "" : clientName);
|
msg.Write(clientName==null ? "" : clientName);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -741,6 +781,10 @@ namespace Barotrauma
|
|||||||
//float durationScroll = 0.0f;
|
//float durationScroll = 0.0f;
|
||||||
string levelSeed = "";
|
string levelSeed = "";
|
||||||
|
|
||||||
|
bool autoRestart = false;
|
||||||
|
|
||||||
|
float restartTimer = 0.0f;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mapName = msg.ReadString();
|
mapName = msg.ReadString();
|
||||||
@@ -755,6 +799,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
levelSeed = msg.ReadString();
|
levelSeed = msg.ReadString();
|
||||||
|
|
||||||
|
autoRestart = msg.ReadBoolean();
|
||||||
|
restartTimer = msg.ReadFloat();
|
||||||
|
|
||||||
int playerCount = msg.ReadByte();
|
int playerCount = msg.ReadByte();
|
||||||
|
|
||||||
playerList.ClearChildren();
|
playerList.ClearChildren();
|
||||||
@@ -773,6 +820,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
modeList.Select(modeIndex);
|
modeList.Select(modeIndex);
|
||||||
|
|
||||||
|
autoRestartBox.Selected = autoRestart;
|
||||||
|
autoRestartTimer = restartTimer;
|
||||||
|
|
||||||
//durationBar.BarScroll = durationScroll;
|
//durationBar.BarScroll = durationScroll;
|
||||||
|
|
||||||
LevelSeed = levelSeed;
|
LevelSeed = levelSeed;
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
new GUITextBlock(new Rectangle(middleX + columnX[0], 30, 0, 30), "Name", GUI.Style, menu);
|
new GUITextBlock(new Rectangle(middleX + columnX[0], 30, 0, 30), "Name", GUI.Style, menu);
|
||||||
new GUITextBlock(new Rectangle(middleX + columnX[1], 30, 0, 30), "Players", GUI.Style, menu);
|
new GUITextBlock(new Rectangle(middleX + columnX[1], 30, 0, 30), "Players", GUI.Style, menu);
|
||||||
new GUITextBlock(new Rectangle(middleX + columnX[2], 30, 0, 30), "Running", GUI.Style, menu);
|
new GUITextBlock(new Rectangle(middleX + columnX[2], 30, 0, 30), "Round started", GUI.Style, menu);
|
||||||
|
|
||||||
joinButton = new GUIButton(new Rectangle(-170, 0, 150, 30), "Refresh", Alignment.BottomRight, GUI.Style, menu);
|
joinButton = new GUIButton(new Rectangle(-170, 0, 150, 30), "Refresh", Alignment.BottomRight, GUI.Style, menu);
|
||||||
joinButton.OnClicked = RefreshServers;
|
joinButton.OnClicked = RefreshServers;
|
||||||
@@ -90,8 +90,7 @@ namespace Barotrauma
|
|||||||
base.Select();
|
base.Select();
|
||||||
|
|
||||||
|
|
||||||
//RefreshServers(null, null);
|
RefreshServers(null, null);
|
||||||
//UpdateServerList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool SelectServer(GUIComponent component, object obj)
|
private bool SelectServer(GUIComponent component, object obj)
|
||||||
|
|||||||
@@ -1,4 +1,20 @@
|
|||||||
|
---------------------------------------------------------------------------------------------------------
|
||||||
|
v0.2.1
|
||||||
|
---------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Multiplayer:
|
||||||
|
- fixed a bug that crashed the game after successfully retrieving an artifact in quest mode
|
||||||
|
- fixed client not disconnecting when going back to the main menu
|
||||||
|
- fixed a bug that caused some map seeds to throw an error
|
||||||
|
- players can be kicked out of the server by selecting them in the player list, not just through
|
||||||
|
the debug console
|
||||||
|
|
||||||
|
Items:
|
||||||
|
- all wires can be used for electrical repairs, not just ones named ''Wire''
|
||||||
|
- broken doors can only be fixed by mechanics
|
||||||
|
- fixed a bug that sometimes made it impossible to pick/select items after reattaching them on a wall
|
||||||
|
- wires are disconnected and dropped if the item at either end is removed
|
||||||
|
|
||||||
---------------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------------
|
||||||
v0.2
|
v0.2
|
||||||
---------------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user