(a00338777) v0.9.2.1
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -118,10 +117,23 @@ namespace Barotrauma.Networking
|
||||
|
||||
public bool IsBanned(IPAddress IP, ulong steamID)
|
||||
{
|
||||
bannedPlayers.RemoveAll(bp => bp.ExpirationTime.HasValue && DateTime.Now > bp.ExpirationTime.Value);
|
||||
if (IPAddress.IsLoopback(IP)) { return false; }
|
||||
return bannedPlayers.Any(bp => bp.CompareTo(IP) || (steamID > 0 && bp.SteamID == steamID));
|
||||
}
|
||||
|
||||
public bool IsBanned(IPAddress IP)
|
||||
{
|
||||
if (IPAddress.IsLoopback(IP)) { return false; }
|
||||
bannedPlayers.RemoveAll(bp => bp.ExpirationTime.HasValue && DateTime.Now > bp.ExpirationTime.Value);
|
||||
return bannedPlayers.Any(bp => bp.CompareTo(IP));
|
||||
}
|
||||
|
||||
public bool IsBanned(ulong steamID)
|
||||
{
|
||||
bannedPlayers.RemoveAll(bp => bp.ExpirationTime.HasValue && DateTime.Now > bp.ExpirationTime.Value);
|
||||
return bannedPlayers.Any(bp => (steamID > 0 && bp.SteamID == steamID));
|
||||
}
|
||||
|
||||
public void BanPlayer(string name, IPAddress ip, string reason, TimeSpan? duration)
|
||||
{
|
||||
string ipStr = ip.IsIPv4MappedToIPv6 ? ip.MapToIPv4().ToString() : ip.ToString();
|
||||
@@ -262,7 +274,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerAdminWrite(NetBuffer outMsg, Client c)
|
||||
public void ServerAdminWrite(IWriteMessage outMsg, Client c)
|
||||
{
|
||||
if (!c.HasPermission(ClientPermissions.Ban))
|
||||
{
|
||||
@@ -273,7 +285,7 @@ namespace Barotrauma.Networking
|
||||
outMsg.Write(c.Connection == GameMain.Server.OwnerConnection);
|
||||
|
||||
outMsg.WritePadBits();
|
||||
outMsg.WriteVariableInt32(bannedPlayers.Count);
|
||||
outMsg.WriteVariableUInt32((UInt32)bannedPlayers.Count);
|
||||
for (int i = 0; i < bannedPlayers.Count; i++)
|
||||
{
|
||||
BannedPlayer bannedPlayer = bannedPlayers[i];
|
||||
@@ -289,14 +301,14 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public bool ServerAdminRead(NetBuffer incMsg, Client c)
|
||||
public bool ServerAdminRead(IReadMessage incMsg, Client c)
|
||||
{
|
||||
if (!c.HasPermission(ClientPermissions.Ban))
|
||||
{
|
||||
UInt16 removeCount = incMsg.ReadUInt16();
|
||||
incMsg.Position += removeCount * 4 * 8;
|
||||
incMsg.BitPosition += removeCount * 4 * 8;
|
||||
UInt16 rangeBanCount = incMsg.ReadUInt16();
|
||||
incMsg.Position += rangeBanCount * 4 * 8;
|
||||
incMsg.BitPosition += rangeBanCount * 4 * 8;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Linq;
|
||||
@@ -9,7 +8,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
partial class ChatMessage
|
||||
{
|
||||
public static void ServerRead(NetIncomingMessage msg, Client c)
|
||||
public static void ServerRead(IReadMessage msg, Client c)
|
||||
{
|
||||
c.KickAFKTimer = 0.0f;
|
||||
|
||||
@@ -61,22 +60,24 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
float similarity = 0.0f;
|
||||
//don't do message similarity checks on order messages
|
||||
if (orderMsg == null)
|
||||
for (int i = 0; i < c.LastSentChatMessages.Count; i++)
|
||||
{
|
||||
for (int i = 0; i < c.LastSentChatMessages.Count; i++)
|
||||
float closeFactor = 1.0f / (c.LastSentChatMessages.Count - i);
|
||||
|
||||
if (string.IsNullOrEmpty(txt))
|
||||
{
|
||||
float closeFactor = 1.0f / (c.LastSentChatMessages.Count - i);
|
||||
if (string.IsNullOrEmpty(txt))
|
||||
{
|
||||
similarity += closeFactor;
|
||||
}
|
||||
else
|
||||
{
|
||||
int levenshteinDist = ToolBox.LevenshteinDistance(txt, c.LastSentChatMessages[i]);
|
||||
similarity += Math.Max((txt.Length - levenshteinDist) / (float)txt.Length * closeFactor, 0.0f);
|
||||
}
|
||||
similarity += closeFactor;
|
||||
}
|
||||
else
|
||||
{
|
||||
int levenshteinDist = ToolBox.LevenshteinDistance(txt, c.LastSentChatMessages[i]);
|
||||
similarity += Math.Max((txt.Length - levenshteinDist) / (float)txt.Length * closeFactor, 0.0f);
|
||||
}
|
||||
}
|
||||
//order/report messages can be sent a little faster than normal messages without triggering the spam filter
|
||||
if (orderMsg != null)
|
||||
{
|
||||
similarity *= 0.25f;
|
||||
}
|
||||
|
||||
bool isOwner = GameMain.Server.OwnerConnection != null && c.Connection == GameMain.Server.OwnerConnection;
|
||||
@@ -153,7 +154,7 @@ namespace Barotrauma.Networking
|
||||
return length;
|
||||
}
|
||||
|
||||
public virtual void ServerWrite(NetOutgoingMessage msg, Client c)
|
||||
public virtual void ServerWrite(IWriteMessage msg, Client c)
|
||||
{
|
||||
msg.Write((byte)ServerNetObject.CHAT_MESSAGE);
|
||||
msg.Write(NetStateID);
|
||||
@@ -168,4 +169,4 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -7,8 +6,6 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
partial class Client : IDisposable
|
||||
{
|
||||
public ulong SteamID;
|
||||
|
||||
public bool VoiceEnabled = true;
|
||||
|
||||
public UInt16 LastRecvClientListUpdate = 0;
|
||||
@@ -61,9 +58,11 @@ namespace Barotrauma.Networking
|
||||
public float DeleteDisconnectedTimer;
|
||||
|
||||
public CharacterInfo CharacterInfo;
|
||||
public NetConnection Connection { get; set; }
|
||||
public NetworkConnection Connection { get; set; }
|
||||
|
||||
public bool SpectateOnly;
|
||||
|
||||
public int KarmaKickCount;
|
||||
|
||||
private float karma = 100.0f;
|
||||
public float Karma
|
||||
@@ -108,28 +107,32 @@ namespace Barotrauma.Networking
|
||||
NeedsMidRoundSync = false;
|
||||
}
|
||||
|
||||
public static bool IsValidName(string name, GameServer server)
|
||||
public static bool IsValidName(string name, ServerSettings serverSettings)
|
||||
{
|
||||
char[] disallowedChars = new char[] { ';', ',', '<', '>', '/', '\\', '[', ']', '"', '?' };
|
||||
if (name.Any(c => disallowedChars.Contains(c))) return false;
|
||||
|
||||
foreach (char character in name)
|
||||
{
|
||||
if (!server.ServerSettings.AllowedClientNameChars.Any(charRange => (int)character >= charRange.First && (int)character <= charRange.Second)) return false;
|
||||
if (!serverSettings.AllowedClientNameChars.Any(charRange => (int)character >= charRange.First && (int)character <= charRange.Second)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IPMatches(string ip)
|
||||
public bool EndpointMatches(string endpoint)
|
||||
{
|
||||
if (Connection?.RemoteEndPoint == null) { return false; }
|
||||
if (Connection.RemoteEndPoint.Address.IsIPv4MappedToIPv6 &&
|
||||
Connection.RemoteEndPoint.Address.MapToIPv4().ToString() == ip)
|
||||
if (Connection is LidgrenConnection lidgrenConn)
|
||||
{
|
||||
return true;
|
||||
if (lidgrenConn.IPEndPoint?.Address == null) { return false; }
|
||||
if ((lidgrenConn.IPEndPoint?.Address.IsIPv4MappedToIPv6 ?? false) &&
|
||||
lidgrenConn.IPEndPoint?.Address.MapToIPv4().ToString() == endpoint)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Connection.RemoteEndPoint.Address.ToString() == ip;
|
||||
|
||||
return Connection.EndPointString == endpoint;
|
||||
}
|
||||
|
||||
public void SetPermissions(ClientPermissions permissions, List<DebugConsole.Command> permittedConsoleCommands)
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWrite(Lidgren.Network.NetBuffer message, Client client, object[] extraData = null)
|
||||
public void ServerWrite(IWriteMessage message, Client client, object[] extraData = null)
|
||||
{
|
||||
if (GameMain.Server == null) return;
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -12,11 +11,11 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
public class FileTransferOut
|
||||
{
|
||||
private byte[] data;
|
||||
private readonly byte[] data;
|
||||
|
||||
private DateTime startingTime;
|
||||
private readonly DateTime startingTime;
|
||||
|
||||
private NetConnection connection;
|
||||
private readonly NetworkConnection connection;
|
||||
|
||||
public FileTransferStatus Status;
|
||||
|
||||
@@ -40,7 +39,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
public float Progress
|
||||
{
|
||||
get { return SentOffset / (float)Data.Length; }
|
||||
get { return KnownReceivedOffset / (float)Data.Length; }
|
||||
}
|
||||
|
||||
public float WaitTimer
|
||||
@@ -54,20 +53,24 @@ namespace Barotrauma.Networking
|
||||
get { return data; }
|
||||
}
|
||||
|
||||
public bool Acknowledged;
|
||||
|
||||
public int SentOffset
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public NetConnection Connection
|
||||
public int KnownReceivedOffset;
|
||||
|
||||
public NetworkConnection Connection
|
||||
{
|
||||
get { return connection; }
|
||||
}
|
||||
|
||||
public int SequenceChannel;
|
||||
public int ID;
|
||||
|
||||
public FileTransferOut(NetConnection recipient, FileTransferType fileType, string filePath)
|
||||
public FileTransferOut(NetworkConnection recipient, FileTransferType fileType, string filePath)
|
||||
{
|
||||
connection = recipient;
|
||||
|
||||
@@ -75,6 +78,10 @@ namespace Barotrauma.Networking
|
||||
FilePath = filePath;
|
||||
FileName = Path.GetFileName(filePath);
|
||||
|
||||
Acknowledged = false;
|
||||
SentOffset = 0;
|
||||
KnownReceivedOffset = 0;
|
||||
|
||||
Status = FileTransferStatus.NotStarted;
|
||||
|
||||
startingTime = DateTime.Now;
|
||||
@@ -105,26 +112,26 @@ namespace Barotrauma.Networking
|
||||
public FileTransferDelegate OnStarted;
|
||||
public FileTransferDelegate OnEnded;
|
||||
|
||||
private List<FileTransferOut> activeTransfers;
|
||||
private readonly List<FileTransferOut> activeTransfers;
|
||||
|
||||
private int chunkLen;
|
||||
private readonly int chunkLen;
|
||||
|
||||
private NetPeer peer;
|
||||
private readonly ServerPeer peer;
|
||||
|
||||
public List<FileTransferOut> ActiveTransfers
|
||||
{
|
||||
get { return activeTransfers; }
|
||||
}
|
||||
|
||||
public FileSender(NetworkMember networkMember)
|
||||
public FileSender(ServerPeer serverPeer, int mtu)
|
||||
{
|
||||
peer = networkMember.NetPeer;
|
||||
chunkLen = peer.Configuration.MaximumTransmissionUnit - 100;
|
||||
peer = serverPeer;
|
||||
chunkLen = mtu - 100;
|
||||
|
||||
activeTransfers = new List<FileTransferOut>();
|
||||
}
|
||||
|
||||
public FileTransferOut StartTransfer(NetConnection recipient, FileTransferType fileType, string filePath)
|
||||
public FileTransferOut StartTransfer(NetworkConnection recipient, FileTransferType fileType, string filePath)
|
||||
{
|
||||
if (activeTransfers.Count >= MaxTransferCount)
|
||||
{
|
||||
@@ -147,11 +154,11 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
transfer = new FileTransferOut(recipient, fileType, filePath)
|
||||
{
|
||||
SequenceChannel = 1
|
||||
ID = 1
|
||||
};
|
||||
while (activeTransfers.Any(t => t.Connection == recipient && t.SequenceChannel == transfer.SequenceChannel))
|
||||
while (activeTransfers.Any(t => t.Connection == recipient && t.ID == transfer.ID))
|
||||
{
|
||||
transfer.SequenceChannel++;
|
||||
transfer.ID++;
|
||||
}
|
||||
activeTransfers.Add(transfer);
|
||||
}
|
||||
@@ -168,10 +175,10 @@ namespace Barotrauma.Networking
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
activeTransfers.RemoveAll(t => t.Connection.Status != NetConnectionStatus.Connected);
|
||||
activeTransfers.RemoveAll(t => t.Connection.Status != NetworkConnectionStatus.Connected);
|
||||
|
||||
var endedTransfers = activeTransfers.FindAll(t =>
|
||||
t.Connection.Status != NetConnectionStatus.Connected ||
|
||||
t.Connection.Status != NetworkConnectionStatus.Connected ||
|
||||
t.Status == FileTransferStatus.Finished ||
|
||||
t.Status == FileTransferStatus.Canceled ||
|
||||
t.Status == FileTransferStatus.Error);
|
||||
@@ -187,78 +194,95 @@ namespace Barotrauma.Networking
|
||||
transfer.WaitTimer -= deltaTime;
|
||||
if (transfer.WaitTimer > 0.0f) continue;
|
||||
|
||||
if (!transfer.Connection.CanSendImmediately(NetDeliveryMethod.ReliableOrdered, transfer.SequenceChannel)) continue;
|
||||
|
||||
transfer.WaitTimer = 0.05f;// transfer.Connection.AverageRoundtripTime;
|
||||
|
||||
// send another part of the file
|
||||
long remaining = transfer.Data.Length - transfer.SentOffset;
|
||||
int sendByteCount = (remaining > chunkLen ? chunkLen : (int)remaining);
|
||||
|
||||
NetOutgoingMessage message;
|
||||
IWriteMessage message;
|
||||
|
||||
//first message; send length, chunk length, file name etc
|
||||
if (transfer.SentOffset == 0)
|
||||
try
|
||||
{
|
||||
message = peer.CreateMessage();
|
||||
message.Write((byte)ServerPacketHeader.FILE_TRANSFER);
|
||||
|
||||
//if the recipient is the owner of the server (= a client running the server from the main exe)
|
||||
//we don't need to send anything, the client can just read the file directly
|
||||
if (transfer.Connection == GameMain.Server.OwnerConnection)
|
||||
//first message; send length, file name etc
|
||||
//wait for acknowledgement before sending data
|
||||
if (!transfer.Acknowledged)
|
||||
{
|
||||
message.Write((byte)FileTransferMessageType.TransferOnSameMachine);
|
||||
message.Write((byte)transfer.FileType);
|
||||
message.Write(transfer.FilePath);
|
||||
GameMain.Server.CompressOutgoingMessage(message);
|
||||
transfer.Connection.SendMessage(message, NetDeliveryMethod.ReliableOrdered, transfer.SequenceChannel);
|
||||
transfer.Status = FileTransferStatus.Finished;
|
||||
message = new WriteOnlyMessage();
|
||||
message.Write((byte)ServerPacketHeader.FILE_TRANSFER);
|
||||
|
||||
//if the recipient is the owner of the server (= a client running the server from the main exe)
|
||||
//we don't need to send anything, the client can just read the file directly
|
||||
if (transfer.Connection == GameMain.Server.OwnerConnection)
|
||||
{
|
||||
message.Write((byte)FileTransferMessageType.TransferOnSameMachine);
|
||||
message.Write((byte)transfer.ID);
|
||||
message.Write((byte)transfer.FileType);
|
||||
message.Write(transfer.FilePath);
|
||||
peer.Send(message, transfer.Connection, DeliveryMethod.Unreliable);
|
||||
transfer.Status = FileTransferStatus.Finished;
|
||||
}
|
||||
else
|
||||
{
|
||||
message.Write((byte)FileTransferMessageType.Initiate);
|
||||
message.Write((byte)transfer.ID);
|
||||
message.Write((byte)transfer.FileType);
|
||||
//message.Write((ushort)chunkLen);
|
||||
message.Write(transfer.Data.Length);
|
||||
message.Write(transfer.FileName);
|
||||
peer.Send(message, transfer.Connection, DeliveryMethod.Unreliable);
|
||||
|
||||
transfer.Status = FileTransferStatus.Sending;
|
||||
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
DebugConsole.Log("Sending file transfer initiation message: ");
|
||||
DebugConsole.Log(" File: " + transfer.FileName);
|
||||
DebugConsole.Log(" Size: " + transfer.Data.Length);
|
||||
DebugConsole.Log(" ID: " + transfer.ID);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
message = new WriteOnlyMessage();
|
||||
message.Write((byte)ServerPacketHeader.FILE_TRANSFER);
|
||||
message.Write((byte)FileTransferMessageType.Data);
|
||||
|
||||
message.Write((byte)transfer.ID);
|
||||
message.Write(transfer.SentOffset);
|
||||
|
||||
byte[] sendBytes = new byte[sendByteCount];
|
||||
Array.Copy(transfer.Data, transfer.SentOffset, sendBytes, 0, sendByteCount);
|
||||
|
||||
message.Write((ushort)sendByteCount);
|
||||
message.Write(sendBytes, 0, sendByteCount);
|
||||
|
||||
transfer.SentOffset += sendByteCount;
|
||||
if (transfer.SentOffset > transfer.KnownReceivedOffset + chunkLen * 5 ||
|
||||
transfer.SentOffset >= transfer.Data.Length)
|
||||
{
|
||||
message.Write((byte)FileTransferMessageType.Initiate);
|
||||
message.Write((byte)transfer.FileType);
|
||||
message.Write((ushort)chunkLen);
|
||||
message.Write((ulong)transfer.Data.Length);
|
||||
message.Write(transfer.FileName);
|
||||
GameMain.Server.CompressOutgoingMessage(message);
|
||||
transfer.Connection.SendMessage(message, NetDeliveryMethod.ReliableOrdered, transfer.SequenceChannel);
|
||||
|
||||
transfer.Status = FileTransferStatus.Sending;
|
||||
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
DebugConsole.Log("Sending file transfer initiation message: ");
|
||||
DebugConsole.Log(" File: " + transfer.FileName);
|
||||
DebugConsole.Log(" Size: " + transfer.Data.Length);
|
||||
DebugConsole.Log(" Sequence channel: " + transfer.SequenceChannel);
|
||||
}
|
||||
transfer.SentOffset = transfer.KnownReceivedOffset;
|
||||
}
|
||||
|
||||
peer.Send(message, transfer.Connection, DeliveryMethod.Unreliable);
|
||||
}
|
||||
|
||||
message = peer.CreateMessage(1 + 1 + sendByteCount);
|
||||
message.Write((byte)ServerPacketHeader.FILE_TRANSFER);
|
||||
message.Write((byte)FileTransferMessageType.Data);
|
||||
|
||||
byte[] sendBytes = new byte[sendByteCount];
|
||||
Array.Copy(transfer.Data, transfer.SentOffset, sendBytes, 0, sendByteCount);
|
||||
|
||||
message.Write(sendBytes);
|
||||
|
||||
GameMain.Server.CompressOutgoingMessage(message);
|
||||
transfer.Connection.SendMessage(message, NetDeliveryMethod.ReliableOrdered, transfer.SequenceChannel);
|
||||
transfer.SentOffset += sendByteCount;
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("FileSender threw an exception when trying to send data", e);
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"FileSender.Update:Exception",
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"FileSender threw an exception when trying to send data:\n" + e.Message + "\n" + e.StackTrace);
|
||||
transfer.Status = FileTransferStatus.Error;
|
||||
break;
|
||||
}
|
||||
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
DebugConsole.Log("Sending " + sendByteCount + " bytes of the file " + transfer.FileName + " (" + transfer.SentOffset + "/" + transfer.Data.Length + " sent)");
|
||||
}
|
||||
|
||||
if (remaining - sendByteCount <= 0)
|
||||
{
|
||||
transfer.Status = FileTransferStatus.Finished;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,18 +296,35 @@ namespace Barotrauma.Networking
|
||||
GameMain.Server.SendCancelTransferMsg(transfer);
|
||||
}
|
||||
|
||||
public void ReadFileRequest(NetIncomingMessage inc, Client client)
|
||||
public void ReadFileRequest(IReadMessage inc, Client client)
|
||||
{
|
||||
byte messageType = inc.ReadByte();
|
||||
|
||||
if (messageType == (byte)FileTransferMessageType.Cancel)
|
||||
{
|
||||
byte sequenceChannel = inc.ReadByte();
|
||||
var matchingTransfer = activeTransfers.Find(t => t.Connection == inc.SenderConnection && t.SequenceChannel == sequenceChannel);
|
||||
byte transferId = inc.ReadByte();
|
||||
var matchingTransfer = activeTransfers.Find(t => t.Connection == inc.Sender && t.ID == transferId);
|
||||
if (matchingTransfer != null) CancelTransfer(matchingTransfer);
|
||||
|
||||
return;
|
||||
}
|
||||
else if (messageType == (byte)FileTransferMessageType.Data)
|
||||
{
|
||||
byte transferId = inc.ReadByte();
|
||||
var matchingTransfer = activeTransfers.Find(t => t.Connection == inc.Sender && t.ID == transferId);
|
||||
if (matchingTransfer != null)
|
||||
{
|
||||
matchingTransfer.Acknowledged = true;
|
||||
int offset = inc.ReadInt32();
|
||||
matchingTransfer.KnownReceivedOffset = offset > matchingTransfer.KnownReceivedOffset ? offset : matchingTransfer.KnownReceivedOffset;
|
||||
if (matchingTransfer.SentOffset < matchingTransfer.KnownReceivedOffset) { matchingTransfer.SentOffset = matchingTransfer.KnownReceivedOffset; }
|
||||
|
||||
if (matchingTransfer.KnownReceivedOffset >= matchingTransfer.Data.Length)
|
||||
{
|
||||
matchingTransfer.Status = FileTransferStatus.Finished;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte fileType = inc.ReadByte();
|
||||
switch (fileType)
|
||||
@@ -295,17 +336,17 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (requestedSubmarine != null)
|
||||
{
|
||||
StartTransfer(inc.SenderConnection, FileTransferType.Submarine, requestedSubmarine.FilePath);
|
||||
StartTransfer(inc.Sender, FileTransferType.Submarine, requestedSubmarine.FilePath);
|
||||
}
|
||||
break;
|
||||
case (byte)FileTransferType.CampaignSave:
|
||||
if (GameMain.GameSession != null &&
|
||||
!ActiveTransfers.Any(t => t.Connection == inc.SenderConnection && t.FileType == FileTransferType.CampaignSave))
|
||||
!ActiveTransfers.Any(t => t.Connection == inc.Sender && t.FileType == FileTransferType.CampaignSave))
|
||||
{
|
||||
StartTransfer(inc.SenderConnection, FileTransferType.CampaignSave, GameMain.GameSession.SavePath);
|
||||
StartTransfer(inc.Sender, FileTransferType.CampaignSave, GameMain.GameSession.SavePath);
|
||||
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign)
|
||||
{
|
||||
client.LastCampaignSaveSendTime = new Pair<ushort, float>(campaign.LastSaveID, (float)NetTime.Now);
|
||||
client.LastCampaignSaveSendTime = new Pair<ushort, float>(campaign.LastSaveID, (float)Lidgren.Network.NetTime.Now);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,539 +0,0 @@
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class UnauthenticatedClient
|
||||
{
|
||||
public readonly NetConnection Connection;
|
||||
public readonly ulong SteamID;
|
||||
public Facepunch.Steamworks.ServerAuth.Status? SteamAuthStatus = null;
|
||||
public readonly int Nonce;
|
||||
|
||||
public int FailedAttempts;
|
||||
|
||||
public float AuthTimer;
|
||||
|
||||
public UnauthenticatedClient(NetConnection connection, int nonce, ulong steamID = 0)
|
||||
{
|
||||
Connection = connection;
|
||||
SteamID = steamID;
|
||||
Nonce = nonce;
|
||||
AuthTimer = 10.0f;
|
||||
FailedAttempts = 0;
|
||||
}
|
||||
}
|
||||
|
||||
partial class GameServer : NetworkMember
|
||||
{
|
||||
private Int32 ownerKey = 0;
|
||||
|
||||
List<UnauthenticatedClient> unauthenticatedClients = new List<UnauthenticatedClient>();
|
||||
|
||||
private void ReadClientSteamAuthRequest(NetIncomingMessage inc, NetConnection senderConnection, out ulong clientSteamID)
|
||||
{
|
||||
clientSteamID = 0;
|
||||
if (!Steam.SteamManager.USE_STEAM)
|
||||
{
|
||||
DebugConsole.Log("Received a Steam auth request from " + senderConnection.RemoteEndPoint + ". Steam authentication not required, handling auth normally.");
|
||||
//not using steam, handle auth normally
|
||||
HandleClientAuthRequest(senderConnection, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (senderConnection == OwnerConnection)
|
||||
{
|
||||
//the client is the owner of the server, no need for authentication
|
||||
//(it would fail with a "duplicate request" error anyway)
|
||||
HandleClientAuthRequest(senderConnection, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
clientSteamID = inc.ReadUInt64();
|
||||
int authTicketLength = inc.ReadInt32();
|
||||
inc.ReadBytes(authTicketLength, out byte[] authTicketData);
|
||||
|
||||
DebugConsole.Log("Received a Steam auth request");
|
||||
DebugConsole.Log(" Steam ID: "+ clientSteamID);
|
||||
DebugConsole.Log(" Auth ticket length: " + authTicketLength);
|
||||
DebugConsole.Log(" Auth ticket data: " +
|
||||
((authTicketData == null) ? "null" : ToolBox.LimitString(string.Concat(authTicketData.Select(b => b.ToString("X2"))), 16)));
|
||||
|
||||
if (senderConnection != OwnerConnection &&
|
||||
serverSettings.BanList.IsBanned(senderConnection.RemoteEndPoint.Address, clientSteamID))
|
||||
{
|
||||
return;
|
||||
}
|
||||
ulong steamID = clientSteamID;
|
||||
if (unauthenticatedClients.Any(uc => uc.Connection == inc.SenderConnection))
|
||||
{
|
||||
var steamAuthedClient = unauthenticatedClients.Find(uc =>
|
||||
uc.Connection == inc.SenderConnection &&
|
||||
uc.SteamID == steamID &&
|
||||
uc.SteamAuthStatus == Facepunch.Steamworks.ServerAuth.Status.OK);
|
||||
if (steamAuthedClient != null)
|
||||
{
|
||||
DebugConsole.Log("Client already authenticated, sending AUTH_RESPONSE again...");
|
||||
HandleClientAuthRequest(inc.SenderConnection, steamID);
|
||||
}
|
||||
DebugConsole.Log("Steam authentication already pending...");
|
||||
return;
|
||||
}
|
||||
|
||||
if (authTicketData == null)
|
||||
{
|
||||
DebugConsole.Log("Invalid request");
|
||||
return;
|
||||
}
|
||||
|
||||
unauthenticatedClients.RemoveAll(uc => uc.Connection == senderConnection);
|
||||
int nonce = CryptoRandom.Instance.Next();
|
||||
var unauthClient = new UnauthenticatedClient(senderConnection, nonce, clientSteamID)
|
||||
{
|
||||
AuthTimer = 20
|
||||
};
|
||||
unauthenticatedClients.Add(unauthClient);
|
||||
|
||||
if (!Steam.SteamManager.StartAuthSession(authTicketData, clientSteamID))
|
||||
{
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
if (GameMain.Config.RequireSteamAuthentication)
|
||||
{
|
||||
unauthClient.Connection.Disconnect(DisconnectReason.SteamAuthenticationFailed.ToString());
|
||||
Log("Disconnected unauthenticated client (Steam ID: " + steamID + "). Steam authentication failed.", ServerLog.MessageType.ServerMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.Log("Steam authentication failed, skipping to basic auth...");
|
||||
HandleClientAuthRequest(senderConnection);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public void OnAuthChange(ulong steamID, ulong ownerID, Facepunch.Steamworks.ServerAuth.Status status)
|
||||
{
|
||||
DebugConsole.Log("************ OnAuthChange");
|
||||
DebugConsole.Log(" Steam ID: " + steamID);
|
||||
DebugConsole.Log(" Owner ID: " + ownerID);
|
||||
DebugConsole.Log(" Status: " + status);
|
||||
|
||||
UnauthenticatedClient unauthClient = unauthenticatedClients.Find(uc => uc.SteamID == ownerID);
|
||||
if (unauthClient != null)
|
||||
{
|
||||
unauthClient.SteamAuthStatus = status;
|
||||
switch (status)
|
||||
{
|
||||
case Facepunch.Steamworks.ServerAuth.Status.OK:
|
||||
////steam authentication done, check password next
|
||||
Log("Successfully authenticated client via Steam (Steam ID: " + steamID + ").", ServerLog.MessageType.ServerMessage);
|
||||
HandleClientAuthRequest(unauthClient.Connection, unauthClient.SteamID);
|
||||
break;
|
||||
default:
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
if (GameMain.Config.RequireSteamAuthentication)
|
||||
{
|
||||
Log("Disconnected unauthenticated client (Steam ID: " + steamID + "). Steam authentication failed, (" + status + ").", ServerLog.MessageType.ServerMessage);
|
||||
unauthClient.Connection.Disconnect(DisconnectReason.SteamAuthenticationFailed.ToString() + "/ (" + status.ToString() + ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.Log("Steam authentication failed (" + status.ToString() + "), skipping to basic auth...");
|
||||
HandleClientAuthRequest(unauthClient.Connection);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.Log(" No unauthenticated clients found with the Steam ID " + steamID);
|
||||
}
|
||||
|
||||
//kick connected client if status becomes invalid (e.g. VAC banned, not connected to steam)
|
||||
/*if (status != Facepunch.Steamworks.ServerAuth.Status.OK && GameMain.Config.RequireSteamAuthentication)
|
||||
{
|
||||
var connectedClient = connectedClients.Find(c => c.SteamID == ownerID);
|
||||
if (connectedClient != null)
|
||||
{
|
||||
Log("Disconnecting client " + connectedClient.Name + " (Steam ID: " + steamID + "). Steam authentication no longer valid (" + status + ").", ServerLog.MessageType.ServerMessage);
|
||||
KickClient(connectedClient, $"DisconnectMessage.SteamAuthNoLongerValid~[status]={status.ToString()}");
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
private bool IsServerOwner(NetIncomingMessage inc, NetConnection senderConnection)
|
||||
{
|
||||
string address = senderConnection.RemoteEndPoint.Address.MapToIPv4().ToString();
|
||||
int incKey = inc.ReadInt32();
|
||||
|
||||
if (ownerKey == 0)
|
||||
{
|
||||
return false; //ownership key has been destroyed or has never existed
|
||||
}
|
||||
if (address.ToString() != "127.0.0.1")
|
||||
{
|
||||
return false; //not localhost
|
||||
}
|
||||
|
||||
if (incKey != ownerKey)
|
||||
{
|
||||
return false; //incorrect owner key, how did this even happen
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void HandleOwnership(NetIncomingMessage inc, NetConnection senderConnection)
|
||||
{
|
||||
DebugConsole.Log("HandleOwnership (" + senderConnection.RemoteEndPoint.Address + ")");
|
||||
if (IsServerOwner(inc, senderConnection))
|
||||
{
|
||||
ownerKey = 0; //destroy owner key so nobody else can take ownership of the server
|
||||
OwnerConnection = senderConnection;
|
||||
DebugConsole.NewMessage("Successfully set up server owner", Color.Lime);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleClientAuthRequest(NetConnection connection, ulong steamID = 0)
|
||||
{
|
||||
DebugConsole.Log("HandleClientAuthRequest (steamID " + steamID + ")");
|
||||
|
||||
if (GameMain.Config.RequireSteamAuthentication && connection != OwnerConnection && steamID == 0)
|
||||
{
|
||||
DebugConsole.Log("Disconnecting " + connection.RemoteEndPoint + ", Steam authentication required.");
|
||||
connection.Disconnect(DisconnectReason.SteamAuthenticationRequired.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
//client wants to know if server requires password
|
||||
if (ConnectedClients.Find(c => c.Connection == connection) != null)
|
||||
{
|
||||
//this client has already been authenticated
|
||||
return;
|
||||
}
|
||||
|
||||
UnauthenticatedClient unauthClient = unauthenticatedClients.Find(uc => uc.Connection == connection);
|
||||
if (unauthClient == null)
|
||||
{
|
||||
DebugConsole.Log("Unauthed client, generating a nonce...");
|
||||
//new client, generate nonce and add to unauth queue
|
||||
if (ConnectedClients.Count >= serverSettings.MaxPlayers)
|
||||
{
|
||||
//server is full, can't allow new connection
|
||||
connection.Disconnect(DisconnectReason.ServerFull.ToString());
|
||||
if (steamID > 0) { Steam.SteamManager.StopAuthSession(steamID); }
|
||||
return;
|
||||
}
|
||||
|
||||
int nonce = CryptoRandom.Instance.Next();
|
||||
unauthClient = new UnauthenticatedClient(connection, nonce, steamID);
|
||||
unauthenticatedClients.Add(unauthClient);
|
||||
}
|
||||
unauthClient.AuthTimer = 10.0f;
|
||||
//if the client is already in the queue, getting another unauth request means that our response was lost; resend
|
||||
NetOutgoingMessage nonceMsg = server.CreateMessage();
|
||||
nonceMsg.Write((byte)ServerPacketHeader.AUTH_RESPONSE);
|
||||
if (serverSettings.HasPassword && connection != OwnerConnection)
|
||||
{
|
||||
nonceMsg.Write(true); //true = password
|
||||
nonceMsg.Write((Int32)unauthClient.Nonce); //here's nonce, encrypt with this
|
||||
}
|
||||
else
|
||||
{
|
||||
nonceMsg.Write(false); //false = no password
|
||||
}
|
||||
CompressOutgoingMessage(nonceMsg);
|
||||
DebugConsole.Log("Sending auth response...");
|
||||
server.SendMessage(nonceMsg, connection, NetDeliveryMethod.Unreliable);
|
||||
}
|
||||
|
||||
private void ClientInitRequest(NetIncomingMessage inc)
|
||||
{
|
||||
DebugConsole.Log("Received client init request");
|
||||
if (ConnectedClients.Find(c => c.Connection == inc.SenderConnection) != null)
|
||||
{
|
||||
//this client was already authenticated
|
||||
//another init request means they didn't get any update packets yet
|
||||
DebugConsole.Log("Client already connected, ignoring...");
|
||||
return;
|
||||
}
|
||||
|
||||
UnauthenticatedClient unauthClient = unauthenticatedClients.Find(uc => uc.Connection == inc.SenderConnection);
|
||||
if (unauthClient == null)
|
||||
{
|
||||
//client did not ask for nonce first, can't authorize
|
||||
inc.SenderConnection.Disconnect(DisconnectReason.AuthenticationRequired.ToString());
|
||||
if (unauthClient.SteamID > 0) { Steam.SteamManager.StopAuthSession(unauthClient.SteamID); }
|
||||
return;
|
||||
}
|
||||
|
||||
if (serverSettings.HasPassword && inc.SenderConnection != OwnerConnection)
|
||||
{
|
||||
//decrypt message and compare password
|
||||
string clPw = inc.ReadString();
|
||||
if (!serverSettings.IsPasswordCorrect(clPw, unauthClient.Nonce))
|
||||
{
|
||||
unauthClient.FailedAttempts++;
|
||||
if (unauthClient.FailedAttempts > 3)
|
||||
{
|
||||
//disconnect and ban after too many failed attempts
|
||||
serverSettings.BanList.BanPlayer("Unnamed", unauthClient.Connection.RemoteEndPoint.Address, "DisconnectMessage.TooManyFailedLogins", duration: null);
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.TooManyFailedLogins, "");
|
||||
|
||||
Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " has been banned from the server (too many wrong passwords)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " has been banned from the server (too many wrong passwords)", Color.Red);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//not disconnecting the player here, because they'll still use the same connection and nonce if they try logging in again
|
||||
NetOutgoingMessage reject = server.CreateMessage();
|
||||
reject.Write((byte)ServerPacketHeader.AUTH_FAILURE);
|
||||
reject.Write("Wrong password! You have " + Convert.ToString(4 - unauthClient.FailedAttempts) + " more attempts before you're banned from the server.");
|
||||
Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " failed to join the server (incorrect password)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " failed to join the server (incorrect password)", Color.Red);
|
||||
CompressOutgoingMessage(reject);
|
||||
server.SendMessage(reject, unauthClient.Connection, NetDeliveryMethod.Unreliable);
|
||||
unauthClient.AuthTimer = 10.0f;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
string clVersion = inc.ReadString();
|
||||
|
||||
UInt16 contentPackageCount = inc.ReadUInt16();
|
||||
List<string> contentPackageNames = new List<string>();
|
||||
List<string> contentPackageHashes = new List<string>();
|
||||
for (int i = 0; i < contentPackageCount; i++)
|
||||
{
|
||||
string packageName = inc.ReadString();
|
||||
string packageHash = inc.ReadString();
|
||||
contentPackageNames.Add(packageName);
|
||||
contentPackageHashes.Add(packageHash);
|
||||
if (contentPackageCount == 0)
|
||||
{
|
||||
DebugConsole.Log("Client is using content package " +
|
||||
(packageName ?? "null") + " (" + (packageHash ?? "null" + ")"));
|
||||
}
|
||||
}
|
||||
|
||||
if (contentPackageCount == 0)
|
||||
{
|
||||
DebugConsole.Log("Client did not list any content packages.");
|
||||
}
|
||||
|
||||
string clName = Client.SanitizeName(inc.ReadString());
|
||||
if (string.IsNullOrWhiteSpace(clName))
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NoName, "");
|
||||
|
||||
Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " couldn't join the server (no name given)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " couldn't join the server (no name given)", Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
bool? isCompatibleVersion = IsCompatible(clVersion, GameMain.Version.ToString());
|
||||
if (isCompatibleVersion.HasValue && !isCompatibleVersion.Value)
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.InvalidVersion,
|
||||
$"DisconnectMessage.InvalidVersion~[version]={GameMain.Version.ToString()}~[clientversion]={clVersion}");
|
||||
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible game version)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible game version)", Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
//check if the client is missing any of the content packages the server requires
|
||||
List<ContentPackage> missingPackages = new List<ContentPackage>();
|
||||
foreach (ContentPackage contentPackage in GameMain.SelectedPackages)
|
||||
{
|
||||
if (!contentPackage.HasMultiplayerIncompatibleContent) continue;
|
||||
bool packageFound = false;
|
||||
for (int i = 0; i < contentPackageCount; i++)
|
||||
{
|
||||
if (contentPackageNames[i] == contentPackage.Name && contentPackageHashes[i] == contentPackage.MD5hash.Hash)
|
||||
{
|
||||
packageFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!packageFound) missingPackages.Add(contentPackage);
|
||||
}
|
||||
|
||||
if (missingPackages.Count == 1)
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.MissingContentPackage, $"DisconnectMessage.MissingContentPackage~[missingcontentpackage]={GetPackageStr(missingPackages[0])}");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (missing content package " + GetPackageStr(missingPackages[0]) + ")", ServerLog.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
else if (missingPackages.Count > 1)
|
||||
{
|
||||
List<string> packageStrs = new List<string>();
|
||||
missingPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.MissingContentPackage, $"DisconnectMessage.MissingContentPackages~[missingcontentpackages]={string.Join(", ", packageStrs)}");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (missing content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
string GetPackageStr(ContentPackage contentPackage)
|
||||
{
|
||||
return "\"" + contentPackage.Name + "\" (hash " + contentPackage.MD5hash.ShortHash + ")";
|
||||
}
|
||||
|
||||
//check if the client is using any contentpackages that are not compatible with the server
|
||||
List<Pair<string, string>> incompatiblePackages = new List<Pair<string, string>>();
|
||||
for (int i = 0; i < contentPackageNames.Count; i++)
|
||||
{
|
||||
if (!GameMain.Config.SelectedContentPackages.Any(cp => cp.Name == contentPackageNames[i] && cp.MD5hash.Hash == contentPackageHashes[i]))
|
||||
{
|
||||
incompatiblePackages.Add(new Pair<string, string>(contentPackageNames[i], contentPackageHashes[i]));
|
||||
}
|
||||
}
|
||||
|
||||
if (incompatiblePackages.Count == 1)
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.IncompatibleContentPackage,
|
||||
$"DisconnectMessage.IncompatibleContentPackage~[incompatiblecontentpackage]={GetPackageStr2(incompatiblePackages[0])}");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible content package " + GetPackageStr2(incompatiblePackages[0]) + ")", ServerLog.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
else if (incompatiblePackages.Count > 1)
|
||||
{
|
||||
List<string> packageStrs = new List<string>();
|
||||
incompatiblePackages.ForEach(cp => packageStrs.Add(GetPackageStr2(cp)));
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.IncompatibleContentPackage,
|
||||
$"DisconnectMessage.IncompatibleContentPackages~[incompatiblecontentpackages]={string.Join(", ", packageStrs)}");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
string GetPackageStr2(Pair<string, string> nameAndHash)
|
||||
{
|
||||
return "\"" + nameAndHash.First + "\" (hash " + Md5Hash.GetShortHash(nameAndHash.Second) + ")";
|
||||
}
|
||||
|
||||
if (inc.SenderConnection != OwnerConnection && !serverSettings.Whitelist.IsWhiteListed(clName, inc.SenderConnection.RemoteEndPoint.Address))
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NotOnWhitelist, "");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (not in whitelist)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (not in whitelist)", Color.Red);
|
||||
return;
|
||||
}
|
||||
if (!Client.IsValidName(clName, this))
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.InvalidName, "");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (invalid name)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (invalid name)", Color.Red);
|
||||
return;
|
||||
}
|
||||
if (inc.SenderConnection != OwnerConnection && Homoglyphs.Compare(clName.ToLower(), Name.ToLower()))
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NameTaken, "");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)", Color.Red);
|
||||
return;
|
||||
}
|
||||
Client nameTaken = ConnectedClients.Find(c => Homoglyphs.Compare(c.Name.ToLower(), clName.ToLower()));
|
||||
if (nameTaken != null)
|
||||
{
|
||||
if (nameTaken.Connection.RemoteEndPoint.Address.ToString() == inc.SenderEndPoint.Address.ToString())
|
||||
{
|
||||
//both name and IP address match, replace this player's connection
|
||||
nameTaken.Connection.Disconnect(DisconnectReason.SessionTaken.ToString());
|
||||
nameTaken.Connection = unauthClient.Connection;
|
||||
nameTaken.InitClientSync(); //reinitialize sync ids because this is a new connection
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
unauthClient = null;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//can't authorize this client
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NameTaken, "");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name already taken)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name already taken)", Color.Red);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//new client
|
||||
Client newClient = new Client(clName, GetNewClientID());
|
||||
newClient.InitClientSync();
|
||||
newClient.Connection = unauthClient.Connection;
|
||||
newClient.SteamID = unauthClient.SteamID;
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
unauthClient = null;
|
||||
ConnectedClients.Add(newClient);
|
||||
|
||||
var previousPlayer = previousPlayers.Find(p => p.MatchesClient(newClient));
|
||||
if (previousPlayer != null)
|
||||
{
|
||||
newClient.Karma = previousPlayer.Karma;
|
||||
foreach (Client c in previousPlayer.KickVoters)
|
||||
{
|
||||
if (!connectedClients.Contains(c)) { continue; }
|
||||
newClient.AddKickVote(c);
|
||||
}
|
||||
}
|
||||
|
||||
LastClientListUpdateID++;
|
||||
|
||||
if (newClient.Connection == OwnerConnection)
|
||||
{
|
||||
newClient.GivePermission(ClientPermissions.All);
|
||||
newClient.PermittedConsoleCommands.AddRange(DebugConsole.Commands);
|
||||
|
||||
GameMain.Server.UpdateClientPermissions(newClient);
|
||||
GameMain.Server.SendConsoleMessage("Granted all permissions to " + newClient.Name + ".", newClient);
|
||||
}
|
||||
|
||||
GameMain.Server.SendChatMessage($"ServerMessage.JoinedServer~[client]={clName}", ChatMessageType.Server, null);
|
||||
serverSettings.ServerDetailsChanged = true;
|
||||
|
||||
if (previousPlayer != null && previousPlayer.Name != newClient.Name)
|
||||
{
|
||||
GameMain.Server.SendChatMessage($"ServerMessage.PreviousClientName~[client]={clName}~[previousname]={previousPlayer.Name}", ChatMessageType.Server, null);
|
||||
previousPlayer.Name = newClient.Name;
|
||||
}
|
||||
|
||||
var savedPermissions = serverSettings.ClientPermissions.Find(cp =>
|
||||
cp.SteamID > 0 ?
|
||||
cp.SteamID == newClient.SteamID :
|
||||
newClient.IPMatches(cp.IP));
|
||||
|
||||
if (savedPermissions != null)
|
||||
{
|
||||
newClient.SetPermissions(savedPermissions.Permissions, savedPermissions.PermittedCommands);
|
||||
}
|
||||
else
|
||||
{
|
||||
var defaultPerms = PermissionPreset.List.Find(p => p.Name == "None");
|
||||
if (defaultPerms != null)
|
||||
{
|
||||
newClient.SetPermissions(defaultPerms.Permissions, defaultPerms.PermittedCommands);
|
||||
}
|
||||
else
|
||||
{
|
||||
newClient.SetPermissions(ClientPermissions.None, new List<DebugConsole.Command>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DisconnectUnauthClient(NetIncomingMessage inc, UnauthenticatedClient unauthClient, DisconnectReason reason, string message)
|
||||
{
|
||||
inc.SenderConnection.Disconnect(reason.ToString() + "/ " + TextManager.GetServerMessage(message));
|
||||
if (unauthClient.SteamID > 0) { Steam.SteamManager.StopAuthSession(unauthClient.SteamID); }
|
||||
if (unauthClient != null)
|
||||
{
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,15 @@ namespace Barotrauma
|
||||
|
||||
foreach (Client bannedClient in bannedClients)
|
||||
{
|
||||
GameMain.Server.BanClient(bannedClient, $"KarmaBanned~[banthreshold]={(int)KickBanThreshold}", duration: TimeSpan.FromSeconds(GameMain.Server.ServerSettings.AutoBanTime));
|
||||
if (bannedClient.KarmaKickCount < KicksBeforeBan)
|
||||
{
|
||||
GameMain.Server.KickClient(bannedClient, $"KarmaKicked~[banthreshold]={(int)KickBanThreshold}", resetKarma: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.BanClient(bannedClient, $"KarmaBanned~[banthreshold]={(int)KickBanThreshold}", duration: TimeSpan.FromSeconds(GameMain.Server.ServerSettings.AutoBanTime));
|
||||
}
|
||||
bannedClient.KarmaKickCount++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +87,7 @@ namespace Barotrauma
|
||||
if (TestMode)
|
||||
{
|
||||
string msg =
|
||||
karmaChange < 0 ? $"You karma has decreased to {client.Karma}" : $"You karma has increased to {client.Karma}";
|
||||
karmaChange < 0 ? $"Your karma has decreased to {client.Karma}" : $"Your karma has increased to {client.Karma}";
|
||||
if (!string.IsNullOrEmpty(debugKarmaChangeReason))
|
||||
{
|
||||
msg += $". Reason: {debugKarmaChangeReason}";
|
||||
@@ -100,17 +108,17 @@ namespace Barotrauma
|
||||
|
||||
private void UpdateClient(Client client, float deltaTime)
|
||||
{
|
||||
if (client.Karma > KarmaDecayThreshold)
|
||||
if (client.Character != null && !client.Character.Removed && !client.Character.IsDead)
|
||||
{
|
||||
client.Karma -= KarmaDecay * deltaTime;
|
||||
}
|
||||
else if (client.Karma < KarmaIncreaseThreshold)
|
||||
{
|
||||
client.Karma += KarmaIncrease * deltaTime;
|
||||
}
|
||||
if (client.Karma > KarmaDecayThreshold)
|
||||
{
|
||||
client.Karma -= KarmaDecay * deltaTime;
|
||||
}
|
||||
else if (client.Karma < KarmaIncreaseThreshold)
|
||||
{
|
||||
client.Karma += KarmaIncrease * deltaTime;
|
||||
}
|
||||
|
||||
if (client.Character != null && !client.Character.Removed)
|
||||
{
|
||||
//increase the strength of the herpes affliction in steps instead of linearly
|
||||
//otherwise clients could determine their exact karma value from the strength
|
||||
float herpesStrength = 0.0f;
|
||||
@@ -129,6 +137,10 @@ namespace Barotrauma
|
||||
else if (existingAffliction != null)
|
||||
{
|
||||
existingAffliction.Strength = herpesStrength;
|
||||
if (herpesStrength <= 0.0f)
|
||||
{
|
||||
client.Character.CharacterHealth.ReduceAffliction(null, "invertcontrols", 100.0f);
|
||||
}
|
||||
}
|
||||
|
||||
//check if the client has disconnected an excessive number of wires
|
||||
@@ -182,19 +194,29 @@ namespace Barotrauma
|
||||
if (target.IsDead || target.Removed) { return; }
|
||||
|
||||
bool isEnemy = target.AIController is EnemyAIController || target.TeamID != attacker.TeamID;
|
||||
if (GameMain.Server.TraitorManager != null)
|
||||
if (GameMain.Server.TraitorManager?.Traitors != null)
|
||||
{
|
||||
if (GameMain.Server.TraitorManager.TraitorList.Any(t => t.Character == target))
|
||||
if (GameMain.Server.TraitorManager.Traitors.Any(t => t.Character == target))
|
||||
{
|
||||
//traitors always count as enemies
|
||||
isEnemy = true;
|
||||
}
|
||||
if (GameMain.Server.TraitorManager.TraitorList.Any(t => t.Character == attacker && t.TargetCharacter == target))
|
||||
if (GameMain.Server.TraitorManager.Traitors.Any(t =>
|
||||
t.Character == attacker &&
|
||||
t.CurrentObjective != null &&
|
||||
t.CurrentObjective.IsEnemy(target)))
|
||||
{
|
||||
//target counts as an enemy to the traitor
|
||||
isEnemy = true;
|
||||
}
|
||||
}
|
||||
|
||||
//attacking/healing clowns has a smaller effect on karma
|
||||
if (target.HasEquippedItem("clownmask") &&
|
||||
target.HasEquippedItem("clowncostume"))
|
||||
{
|
||||
damage *= 0.5f;
|
||||
}
|
||||
|
||||
if (appliedAfflictions != null)
|
||||
{
|
||||
@@ -205,7 +227,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (target.AIController is EnemyAIController || target.TeamID != attacker.TeamID)
|
||||
if (isEnemy)
|
||||
{
|
||||
if (damage > 0)
|
||||
{
|
||||
@@ -242,6 +264,19 @@ namespace Barotrauma
|
||||
if (damageAmount > 0)
|
||||
{
|
||||
if (StructureDamageKarmaDecrease <= 0.0f) { return; }
|
||||
|
||||
if (GameMain.Server.TraitorManager?.Traitors != null)
|
||||
{
|
||||
if (GameMain.Server.TraitorManager.Traitors.Any(t =>
|
||||
t.Character == attacker &&
|
||||
t.CurrentObjective != null &&
|
||||
t.CurrentObjective.HasGoalsOfType<Traitor.GoalFloodPercentOfSub>()))
|
||||
{
|
||||
//traitor tasked to flood the sub -> damaging structures is ok
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Client client = GameMain.Server.ConnectedClients.Find(c => c.Character == attacker);
|
||||
if (client != null)
|
||||
{
|
||||
@@ -327,6 +362,13 @@ namespace Barotrauma
|
||||
Client client = GameMain.Server.ConnectedClients.Find(c => c.Character == target);
|
||||
if (client == null) { return; }
|
||||
|
||||
//all penalties/rewards are halved when wearing a clown costume
|
||||
if (target.HasEquippedItem("clownmask") &&
|
||||
target.HasEquippedItem("clowncostume"))
|
||||
{
|
||||
amount *= 0.5f;
|
||||
}
|
||||
|
||||
client.Karma += amount;
|
||||
if (TestMode)
|
||||
{
|
||||
|
||||
+18
-16
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -32,7 +31,7 @@ namespace Barotrauma.Networking
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Write(NetBuffer msg, Client recipient)
|
||||
public void Write(IWriteMessage msg, Client recipient)
|
||||
{
|
||||
serializable.ServerWrite(msg, recipient, Data);
|
||||
}
|
||||
@@ -66,7 +65,7 @@ namespace Barotrauma.Networking
|
||||
public readonly Client Sender;
|
||||
|
||||
public readonly UInt16 CharacterStateID;
|
||||
public readonly NetBuffer Data;
|
||||
public readonly ReadWriteMessage Data;
|
||||
|
||||
public readonly Character Character;
|
||||
|
||||
@@ -74,7 +73,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
public bool IsProcessed;
|
||||
|
||||
public BufferedEvent(Client sender, Character senderCharacter, UInt16 characterStateID, IClientSerializable targetEntity, NetBuffer data)
|
||||
public BufferedEvent(Client sender, Character senderCharacter, UInt16 characterStateID, IClientSerializable targetEntity, ReadWriteMessage data)
|
||||
{
|
||||
this.Sender = sender;
|
||||
this.Character = senderCharacter;
|
||||
@@ -300,7 +299,7 @@ namespace Barotrauma.Networking
|
||||
/// <summary>
|
||||
/// Writes all the events that the client hasn't received yet into the outgoing message
|
||||
/// </summary>
|
||||
public void Write(Client client, NetOutgoingMessage msg)
|
||||
public void Write(Client client, IWriteMessage msg)
|
||||
{
|
||||
Write(client, msg, out _);
|
||||
}
|
||||
@@ -308,7 +307,7 @@ namespace Barotrauma.Networking
|
||||
/// <summary>
|
||||
/// Writes all the events that the client hasn't received yet into the outgoing message
|
||||
/// </summary>
|
||||
public void Write(Client client, NetOutgoingMessage msg, out List<NetEntityEvent> sentEvents)
|
||||
public void Write(Client client, IWriteMessage msg, out List<NetEntityEvent> sentEvents)
|
||||
{
|
||||
List<NetEntityEvent> eventsToSync = null;
|
||||
if (client.NeedsMidRoundSync)
|
||||
@@ -371,7 +370,7 @@ namespace Barotrauma.Networking
|
||||
foreach (NetEntityEvent entityEvent in sentEvents)
|
||||
{
|
||||
(entityEvent as ServerEntityEvent).Sent = true;
|
||||
client.EntityEventLastSent[entityEvent.ID] = NetTime.Now;
|
||||
client.EntityEventLastSent[entityEvent.ID] = Lidgren.Network.NetTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,9 +398,10 @@ namespace Barotrauma.Networking
|
||||
//find the first event that hasn't been sent in roundtriptime or at all
|
||||
client.EntityEventLastSent.TryGetValue(eventList[i].ID, out double lastSent);
|
||||
|
||||
float minInterval = Math.Max(client.Connection.AverageRoundtripTime, (float)server.UpdateInterval.TotalSeconds * 2);
|
||||
float avgRoundtripTime = 0.01f; //TODO: reimplement client.Connection.AverageRoundtripTime
|
||||
float minInterval = Math.Max(avgRoundtripTime, (float)server.UpdateInterval.TotalSeconds * 2);
|
||||
|
||||
if (lastSent > NetTime.Now - Math.Min(minInterval, 0.5f))
|
||||
if (lastSent > Lidgren.Network.NetTime.Now - Math.Min(minInterval, 0.5f))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -444,7 +444,7 @@ namespace Barotrauma.Networking
|
||||
/// <summary>
|
||||
/// Read the events from the message, ignoring ones we've already received
|
||||
/// </summary>
|
||||
public void Read(NetIncomingMessage msg, Client sender = null)
|
||||
public void Read(IReadMessage msg, Client sender = null)
|
||||
{
|
||||
UInt16 firstEventID = msg.ReadUInt16();
|
||||
int eventCount = msg.ReadByte();
|
||||
@@ -472,7 +472,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
DebugConsole.NewMessage("Received msg " + thisEventID, Color.Red);
|
||||
}
|
||||
msg.Position += msgLength * 8;
|
||||
msg.BitPosition += msgLength * 8;
|
||||
}
|
||||
else if (entity == null)
|
||||
{
|
||||
@@ -486,7 +486,7 @@ namespace Barotrauma.Networking
|
||||
Microsoft.Xna.Framework.Color.Orange);
|
||||
}
|
||||
sender.LastSentEntityEventID++;
|
||||
msg.Position += msgLength * 8;
|
||||
msg.BitPosition += msgLength * 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -497,8 +497,10 @@ namespace Barotrauma.Networking
|
||||
|
||||
UInt16 characterStateID = msg.ReadUInt16();
|
||||
|
||||
NetBuffer buffer = new NetBuffer();
|
||||
buffer.Write(msg.ReadBytes(msgLength - 2));
|
||||
ReadWriteMessage buffer = new ReadWriteMessage();
|
||||
byte[] temp = msg.ReadBytes(msgLength - 2);
|
||||
buffer.Write(temp, 0, msgLength - 2);
|
||||
buffer.BitPosition = 0;
|
||||
BufferEvent(new BufferedEvent(sender, sender.Character, characterStateID, entity, buffer));
|
||||
|
||||
sender.LastSentEntityEventID++;
|
||||
@@ -507,7 +509,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
protected override void WriteEvent(NetBuffer buffer, NetEntityEvent entityEvent, Client recipient = null)
|
||||
protected override void WriteEvent(IWriteMessage buffer, NetEntityEvent entityEvent, Client recipient = null)
|
||||
{
|
||||
var serverEvent = entityEvent as ServerEntityEvent;
|
||||
if (serverEvent == null) return;
|
||||
@@ -515,7 +517,7 @@ namespace Barotrauma.Networking
|
||||
serverEvent.Write(buffer, recipient);
|
||||
}
|
||||
|
||||
protected void ReadEvent(NetBuffer buffer, INetSerializable entity, Client sender = null)
|
||||
protected void ReadEvent(IReadMessage buffer, INetSerializable entity, Client sender = null)
|
||||
{
|
||||
var clientEntity = entity as IClientSerializable;
|
||||
if (clientEntity == null) return;
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
partial class OrderChatMessage : ChatMessage
|
||||
{
|
||||
public override void ServerWrite(NetOutgoingMessage msg, Client c)
|
||||
public override void ServerWrite(IWriteMessage msg, Client c)
|
||||
{
|
||||
msg.Write((byte)ServerNetObject.CHAT_MESSAGE);
|
||||
msg.Write(NetStateID);
|
||||
|
||||
+674
@@ -0,0 +1,674 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Linq;
|
||||
using Lidgren.Network;
|
||||
using Facepunch.Steamworks;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class LidgrenServerPeer : ServerPeer
|
||||
{
|
||||
private ServerSettings serverSettings;
|
||||
|
||||
private NetPeerConfiguration netPeerConfiguration;
|
||||
private NetServer netServer;
|
||||
|
||||
private Facepunch.Steamworks.Server steamServer;
|
||||
|
||||
private class PendingClient
|
||||
{
|
||||
public string Name;
|
||||
public int OwnerKey;
|
||||
public NetConnection Connection;
|
||||
public ConnectionInitialization InitializationStep;
|
||||
public double UpdateTime;
|
||||
public double TimeOut;
|
||||
public int Retries;
|
||||
public UInt64? SteamID;
|
||||
public Int32? PasswordSalt;
|
||||
public bool AuthSessionStarted;
|
||||
|
||||
public PendingClient(NetConnection conn)
|
||||
{
|
||||
OwnerKey = 0;
|
||||
Connection = conn;
|
||||
InitializationStep = ConnectionInitialization.SteamTicketAndVersion;
|
||||
Retries = 0;
|
||||
SteamID = null;
|
||||
PasswordSalt = null;
|
||||
UpdateTime = Timing.TotalTime;
|
||||
TimeOut = 20.0;
|
||||
AuthSessionStarted = false;
|
||||
}
|
||||
}
|
||||
|
||||
private List<LidgrenConnection> connectedClients;
|
||||
private List<PendingClient> pendingClients;
|
||||
|
||||
private List<NetIncomingMessage> incomingLidgrenMessages;
|
||||
|
||||
public LidgrenServerPeer(int? ownKey, ServerSettings settings)
|
||||
{
|
||||
serverSettings = settings;
|
||||
|
||||
netServer = null;
|
||||
|
||||
connectedClients = new List<LidgrenConnection>();
|
||||
pendingClients = new List<PendingClient>();
|
||||
|
||||
incomingLidgrenMessages = new List<NetIncomingMessage>();
|
||||
|
||||
steamServer = null;
|
||||
|
||||
ownerKey = ownKey;
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
if (netServer != null) { return; }
|
||||
|
||||
netPeerConfiguration = new NetPeerConfiguration("barotrauma");
|
||||
netPeerConfiguration.AcceptIncomingConnections = true;
|
||||
netPeerConfiguration.AutoExpandMTU = false;
|
||||
netPeerConfiguration.MaximumConnections = serverSettings.MaxPlayers * 2;
|
||||
netPeerConfiguration.EnableUPnP = serverSettings.EnableUPnP;
|
||||
netPeerConfiguration.Port = serverSettings.Port;
|
||||
|
||||
netPeerConfiguration.DisableMessageType(NetIncomingMessageType.DebugMessage |
|
||||
NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt |
|
||||
NetIncomingMessageType.ErrorMessage | NetIncomingMessageType.Error |
|
||||
NetIncomingMessageType.UnconnectedData);
|
||||
|
||||
netPeerConfiguration.EnableMessageType(NetIncomingMessageType.ConnectionApproval);
|
||||
|
||||
netServer = new NetServer(netPeerConfiguration);
|
||||
|
||||
netServer.Start();
|
||||
|
||||
if (serverSettings.EnableUPnP)
|
||||
{
|
||||
InitUPnP();
|
||||
|
||||
while (DiscoveringUPnP()) { }
|
||||
|
||||
FinishUPnP();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close(string msg=null)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
for (int i=pendingClients.Count-1;i>=0;i--)
|
||||
{
|
||||
RemovePendingClient(pendingClients[i], msg ?? DisconnectReason.ServerShutdown.ToString());
|
||||
}
|
||||
|
||||
for (int i=connectedClients.Count-1;i>=0;i--)
|
||||
{
|
||||
Disconnect(connectedClients[i], msg ?? DisconnectReason.ServerShutdown.ToString());
|
||||
}
|
||||
|
||||
netServer.Shutdown(msg ?? DisconnectReason.ServerShutdown.ToString());
|
||||
|
||||
pendingClients.Clear();
|
||||
connectedClients.Clear();
|
||||
|
||||
netServer = null;
|
||||
|
||||
if (steamServer != null)
|
||||
{
|
||||
steamServer.Auth.OnAuthChange = null;
|
||||
}
|
||||
steamServer = null;
|
||||
|
||||
OnShutdown?.Invoke();
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
if (OnOwnerDetermined != null && OwnerConnection != null)
|
||||
{
|
||||
OnOwnerDetermined?.Invoke(OwnerConnection);
|
||||
OnOwnerDetermined = null;
|
||||
}
|
||||
|
||||
netServer.ReadMessages(incomingLidgrenMessages);
|
||||
|
||||
//process incoming connections first
|
||||
foreach (NetIncomingMessage inc in incomingLidgrenMessages.Where(m => m.MessageType == NetIncomingMessageType.ConnectionApproval))
|
||||
{
|
||||
HandleConnection(inc);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
//after processing connections, go ahead with the rest of the messages
|
||||
foreach (NetIncomingMessage inc in incomingLidgrenMessages.Where(m => m.MessageType != NetIncomingMessageType.ConnectionApproval))
|
||||
{
|
||||
switch (inc.MessageType)
|
||||
{
|
||||
case NetIncomingMessageType.Data:
|
||||
HandleDataMessage(inc);
|
||||
break;
|
||||
case NetIncomingMessageType.StatusChanged:
|
||||
HandleStatusChanged(inc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
string errorMsg = "Server failed to read an incoming message. {" + e + "}\n" + e.StackTrace;
|
||||
GameAnalyticsManager.AddErrorEventOnce("LidgrenServerPeer.Update:ClientReadException" + e.TargetSite.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
#else
|
||||
if (GameSettings.VerboseLogging) { DebugConsole.ThrowError(errorMsg); }
|
||||
#endif
|
||||
}
|
||||
|
||||
for (int i = 0; i < pendingClients.Count; i++)
|
||||
{
|
||||
PendingClient pendingClient = pendingClients[i];
|
||||
UpdatePendingClient(pendingClient, deltaTime);
|
||||
if (i >= pendingClients.Count || pendingClients[i] != pendingClient) { i--; }
|
||||
}
|
||||
|
||||
incomingLidgrenMessages.Clear();
|
||||
}
|
||||
|
||||
private void InitUPnP()
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
netServer.UPnP.ForwardPort(netPeerConfiguration.Port, "barotrauma");
|
||||
if (Steam.SteamManager.USE_STEAM)
|
||||
{
|
||||
netServer.UPnP.ForwardPort(serverSettings.QueryPort, "barotrauma");
|
||||
}
|
||||
}
|
||||
|
||||
private bool DiscoveringUPnP()
|
||||
{
|
||||
if (netServer == null) { return false; }
|
||||
|
||||
return netServer.UPnP.Status == UPnPStatus.Discovering;
|
||||
}
|
||||
|
||||
private void FinishUPnP()
|
||||
{
|
||||
//do nothing
|
||||
}
|
||||
|
||||
private void HandleConnection(NetIncomingMessage inc)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
if (connectedClients.Count >= serverSettings.MaxPlayers)
|
||||
{
|
||||
inc.SenderConnection.Deny(DisconnectReason.ServerFull.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (serverSettings.BanList.IsBanned(inc.SenderConnection.RemoteEndPoint.Address, 0))
|
||||
{
|
||||
//IP banned: deny immediately
|
||||
//TODO: use TextManager
|
||||
inc.SenderConnection.Deny(DisconnectReason.Banned.ToString()+"/ IP banned");
|
||||
return;
|
||||
}
|
||||
|
||||
PendingClient pendingClient = pendingClients.Find(c => c.Connection == inc.SenderConnection);
|
||||
|
||||
if (pendingClient == null)
|
||||
{
|
||||
pendingClient = new PendingClient(inc.SenderConnection);
|
||||
pendingClients.Add(pendingClient);
|
||||
}
|
||||
|
||||
inc.SenderConnection.Approve();
|
||||
}
|
||||
|
||||
private void HandleDataMessage(NetIncomingMessage inc)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
PendingClient pendingClient = pendingClients.Find(c => c.Connection == inc.SenderConnection);
|
||||
|
||||
byte incByte = inc.ReadByte();
|
||||
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
|
||||
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
|
||||
|
||||
if (isConnectionInitializationStep && pendingClient != null)
|
||||
{
|
||||
ReadConnectionInitializationStep(pendingClient, inc);
|
||||
}
|
||||
else if (!isConnectionInitializationStep)
|
||||
{
|
||||
LidgrenConnection conn = connectedClients.Find(c => c.NetConnection == inc.SenderConnection);
|
||||
if (conn == null)
|
||||
{
|
||||
if (pendingClient != null)
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.AuthenticationRequired.ToString()+"/ Received data message from unauthenticated client");
|
||||
}
|
||||
else if (inc.SenderConnection.Status != NetConnectionStatus.Disconnected &&
|
||||
inc.SenderConnection.Status != NetConnectionStatus.Disconnecting)
|
||||
{
|
||||
inc.SenderConnection.Disconnect(DisconnectReason.AuthenticationRequired.ToString() + "/ Received data message from unauthenticated client");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (pendingClient != null) { pendingClients.Remove(pendingClient); }
|
||||
if (serverSettings.BanList.IsBanned(conn.IPEndPoint.Address, conn.SteamID))
|
||||
{
|
||||
Disconnect(conn, DisconnectReason.Banned.ToString()+"/ Received data message from banned client");
|
||||
return;
|
||||
}
|
||||
UInt16 length = inc.ReadUInt16();
|
||||
|
||||
//DebugConsole.NewMessage(isCompressed + " " + isConnectionInitializationStep + " " + (int)incByte + " " + length);
|
||||
|
||||
IReadMessage msg = new ReadOnlyMessage(inc.Data, isCompressed, inc.PositionInBytes, length, conn);
|
||||
OnMessageReceived?.Invoke(conn, msg);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleStatusChanged(NetIncomingMessage inc)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
switch (inc.SenderConnection.Status)
|
||||
{
|
||||
case NetConnectionStatus.Disconnected:
|
||||
string disconnectMsg;
|
||||
LidgrenConnection conn = connectedClients.Find(c => c.NetConnection == inc.SenderConnection);
|
||||
if (conn != null)
|
||||
{
|
||||
if (conn == OwnerConnection)
|
||||
{
|
||||
DebugConsole.NewMessage("Owner disconnected: closing the server...");
|
||||
GameServer.Log("Owner disconnected: closing the server...", ServerLog.MessageType.ServerMessage);
|
||||
Close(DisconnectReason.ServerShutdown.ToString() + "/ Owner disconnected");
|
||||
}
|
||||
else
|
||||
{
|
||||
disconnectMsg = $"ServerMessage.HasDisconnected~[client]={conn.Name}";
|
||||
Disconnect(conn, disconnectMsg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PendingClient pendingClient = pendingClients.Find(c => c.Connection == inc.SenderConnection);
|
||||
if (pendingClient != null)
|
||||
{
|
||||
disconnectMsg = $"ServerMessage.HasDisconnected~[client]={pendingClient.Name}";
|
||||
RemovePendingClient(pendingClient, disconnectMsg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadConnectionInitializationStep(PendingClient pendingClient, NetIncomingMessage inc)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
pendingClient.TimeOut = 20.0;
|
||||
|
||||
ConnectionInitialization initializationStep = (ConnectionInitialization)inc.ReadByte();
|
||||
|
||||
//DebugConsole.NewMessage(initializationStep+" "+pendingClient.InitializationStep);
|
||||
|
||||
if (pendingClient.InitializationStep != initializationStep) return;
|
||||
|
||||
switch (initializationStep)
|
||||
{
|
||||
case ConnectionInitialization.SteamTicketAndVersion:
|
||||
string name = Client.SanitizeName(inc.ReadString());
|
||||
int ownKey = inc.ReadInt32();
|
||||
UInt64 steamId = inc.ReadUInt64();
|
||||
UInt16 ticketLength = inc.ReadUInt16();
|
||||
byte[] ticket = inc.ReadBytes(ticketLength);
|
||||
|
||||
if (!Client.IsValidName(name, serverSettings))
|
||||
{
|
||||
if (OwnerConnection != null ||
|
||||
!IPAddress.IsLoopback(pendingClient.Connection.RemoteEndPoint.Address.MapToIPv4()) &&
|
||||
ownerKey == null || ownKey == 0 && ownKey != ownerKey)
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.InvalidName.ToString() + "/ The name \"" + name + "\" is invalid");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
string version = inc.ReadString();
|
||||
bool isCompatibleVersion = NetworkMember.IsCompatible(version, GameMain.Version.ToString()) ?? false;
|
||||
if (!isCompatibleVersion)
|
||||
{
|
||||
RemovePendingClient(pendingClient,
|
||||
$"DisconnectMessage.InvalidVersion~[version]={GameMain.Version.ToString()}~[clientversion]={version}");
|
||||
|
||||
GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible game version)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(name + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible game version)", Microsoft.Xna.Framework.Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
Int32 contentPackageCount = inc.ReadVariableInt32();
|
||||
List<ClientContentPackage> contentPackages = new List<ClientContentPackage>();
|
||||
for (int i = 0; i < contentPackageCount; i++)
|
||||
{
|
||||
string packageName = inc.ReadString();
|
||||
string packageHash = inc.ReadString();
|
||||
contentPackages.Add(new ClientContentPackage(packageName, packageHash));
|
||||
}
|
||||
|
||||
List<ContentPackage> missingPackages = new List<ContentPackage>();
|
||||
foreach (ContentPackage contentPackage in GameMain.SelectedPackages)
|
||||
{
|
||||
if (!contentPackage.HasMultiplayerIncompatibleContent) continue;
|
||||
bool packageFound = false;
|
||||
for (int i = 0; i < contentPackageCount; i++)
|
||||
{
|
||||
if (contentPackages[i].Name == contentPackage.Name && contentPackages[i].Hash == contentPackage.MD5hash.Hash)
|
||||
{
|
||||
packageFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!packageFound) missingPackages.Add(contentPackage);
|
||||
}
|
||||
|
||||
if (missingPackages.Count == 1)
|
||||
{
|
||||
RemovePendingClient(pendingClient,
|
||||
$"DisconnectMessage.MissingContentPackage~[missingcontentpackage]={GetPackageStr(missingPackages[0])}");
|
||||
GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (missing content package " + GetPackageStr(missingPackages[0]) + ")", ServerLog.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
else if (missingPackages.Count > 1)
|
||||
{
|
||||
List<string> packageStrs = new List<string>();
|
||||
missingPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
|
||||
RemovePendingClient(pendingClient,
|
||||
$"DisconnectMessage.MissingContentPackages~[missingcontentpackages]={string.Join(", ", packageStrs)}");
|
||||
GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (missing content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pendingClient.SteamID == null)
|
||||
{
|
||||
bool requireSteamAuth = GameMain.Config.RequireSteamAuthentication;
|
||||
#if DEBUG
|
||||
requireSteamAuth = false;
|
||||
#endif
|
||||
//steam auth cannot be done (SteamManager not initialized or no ticket given),
|
||||
//but it's not required either -> let the client join without auth
|
||||
if ((!Steam.SteamManager.IsInitialized || ticket.Length == 0) &&
|
||||
!requireSteamAuth)
|
||||
{
|
||||
pendingClient.Name = name;
|
||||
pendingClient.OwnerKey = ownKey;
|
||||
pendingClient.InitializationStep = ConnectionInitialization.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerAuth.StartAuthSessionResult authSessionStartState = Steam.SteamManager.StartAuthSession(ticket, steamId);
|
||||
if (authSessionStartState != ServerAuth.StartAuthSessionResult.OK)
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.SteamAuthenticationFailed.ToString() + "/ Steam auth session failed to start: " + authSessionStartState.ToString());
|
||||
return;
|
||||
}
|
||||
pendingClient.SteamID = steamId;
|
||||
pendingClient.Name = name;
|
||||
pendingClient.OwnerKey = ownKey;
|
||||
pendingClient.AuthSessionStarted = true;
|
||||
}
|
||||
}
|
||||
else //TODO: could remove since this seems impossible
|
||||
{
|
||||
if (pendingClient.SteamID != steamId)
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.SteamAuthenticationFailed.ToString() + "/ SteamID mismatch");
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ConnectionInitialization.Password:
|
||||
int pwLength = inc.ReadByte();
|
||||
byte[] incPassword = new byte[pwLength];
|
||||
inc.ReadBytes(incPassword, 0, pwLength);
|
||||
if (pendingClient.PasswordSalt == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Received password message from client without salt");
|
||||
return;
|
||||
}
|
||||
if (serverSettings.IsPasswordCorrect(incPassword, pendingClient.PasswordSalt.Value))
|
||||
{
|
||||
pendingClient.InitializationStep = ConnectionInitialization.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
pendingClient.Retries++;
|
||||
|
||||
if (pendingClient.Retries >= 3)
|
||||
{
|
||||
string banMsg = "Failed to enter correct password too many times";
|
||||
if (pendingClient.SteamID != null)
|
||||
{
|
||||
serverSettings.BanList.BanPlayer(pendingClient.Name, pendingClient.SteamID.Value, banMsg, null);
|
||||
}
|
||||
serverSettings.BanList.BanPlayer(pendingClient.Name, pendingClient.Connection.RemoteEndPoint.Address, banMsg, null);
|
||||
RemovePendingClient(pendingClient, DisconnectReason.Banned.ToString()+" /"+banMsg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
pendingClient.UpdateTime = Timing.TotalTime;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected struct ClientContentPackage
|
||||
{
|
||||
public string Name;
|
||||
public string Hash;
|
||||
|
||||
public ClientContentPackage(string name, string hash)
|
||||
{
|
||||
Name = name; Hash = hash;
|
||||
}
|
||||
}
|
||||
|
||||
private string GetPackageStr(ContentPackage contentPackage)
|
||||
{
|
||||
return "\"" + contentPackage.Name + "\" (hash " + contentPackage.MD5hash.ShortHash + ")";
|
||||
}
|
||||
|
||||
private void UpdatePendingClient(PendingClient pendingClient, float deltaTime)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
if (serverSettings.BanList.IsBanned(pendingClient.Connection.RemoteEndPoint.Address, pendingClient.SteamID ?? 0))
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.Banned.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
//DebugConsole.NewMessage("pending client status: " + pendingClient.InitializationStep);
|
||||
|
||||
if (connectedClients.Count >= serverSettings.MaxPlayers)
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.ServerFull.ToString());
|
||||
}
|
||||
|
||||
if (pendingClient.InitializationStep == ConnectionInitialization.Success)
|
||||
{
|
||||
LidgrenConnection newConnection = new LidgrenConnection(pendingClient.Name, pendingClient.Connection, pendingClient.SteamID ?? 0);
|
||||
newConnection.Status = NetworkConnectionStatus.Connected;
|
||||
connectedClients.Add(newConnection);
|
||||
pendingClients.Remove(pendingClient);
|
||||
|
||||
if (OwnerConnection == null &&
|
||||
IPAddress.IsLoopback(pendingClient.Connection.RemoteEndPoint.Address.MapToIPv4()) &&
|
||||
ownerKey != null && pendingClient.OwnerKey != 0 && pendingClient.OwnerKey == ownerKey)
|
||||
{
|
||||
ownerKey = null;
|
||||
OwnerConnection = newConnection;
|
||||
}
|
||||
|
||||
OnInitializationComplete?.Invoke(newConnection);
|
||||
}
|
||||
|
||||
|
||||
pendingClient.TimeOut -= deltaTime;
|
||||
if (pendingClient.TimeOut < 0.0)
|
||||
{
|
||||
RemovePendingClient(pendingClient, Lidgren.Network.NetConnection.NoResponseMessage);
|
||||
}
|
||||
|
||||
if (Timing.TotalTime < pendingClient.UpdateTime) { return; }
|
||||
pendingClient.UpdateTime = Timing.TotalTime + 1.0;
|
||||
|
||||
NetOutgoingMessage outMsg = netServer.CreateMessage();
|
||||
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
|
||||
outMsg.Write((byte)pendingClient.InitializationStep);
|
||||
switch (pendingClient.InitializationStep)
|
||||
{
|
||||
case ConnectionInitialization.Password:
|
||||
outMsg.Write(pendingClient.PasswordSalt == null); outMsg.WritePadBits();
|
||||
if (pendingClient.PasswordSalt == null)
|
||||
{
|
||||
pendingClient.PasswordSalt = CryptoRandom.Instance.Next();
|
||||
outMsg.Write(pendingClient.PasswordSalt.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
outMsg.Write(pendingClient.Retries);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
NetSendResult result = netServer.SendMessage(outMsg, pendingClient.Connection, NetDeliveryMethod.ReliableUnordered);
|
||||
//DebugConsole.NewMessage("sent update to pending client: "+result);
|
||||
}
|
||||
|
||||
private void RemovePendingClient(PendingClient pendingClient, string reason)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
if (pendingClients.Contains(pendingClient))
|
||||
{
|
||||
pendingClients.Remove(pendingClient);
|
||||
|
||||
if (pendingClient.AuthSessionStarted)
|
||||
{
|
||||
Steam.SteamManager.StopAuthSession(pendingClient.SteamID.Value);
|
||||
pendingClient.SteamID = null;
|
||||
pendingClient.AuthSessionStarted = false;
|
||||
}
|
||||
|
||||
pendingClient.Connection.Disconnect(reason);
|
||||
}
|
||||
}
|
||||
|
||||
public override void InitializeSteamServerCallbacks(Server steamSrvr)
|
||||
{
|
||||
steamServer = steamSrvr;
|
||||
|
||||
steamServer.Auth.OnAuthChange = OnAuthChange;
|
||||
}
|
||||
|
||||
private void OnAuthChange(ulong steamID, ulong ownerID, ServerAuth.Status status)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
PendingClient pendingClient = pendingClients.Find(c => c.SteamID == steamID);
|
||||
DebugConsole.NewMessage(steamID + " validation: " + status+", "+(pendingClient!=null));
|
||||
|
||||
if (pendingClient == null)
|
||||
{
|
||||
if (status != ServerAuth.Status.OK)
|
||||
{
|
||||
LidgrenConnection connection = connectedClients.Find(c => c.SteamID == steamID);
|
||||
if (connection != null)
|
||||
{
|
||||
Disconnect(connection, DisconnectReason.SteamAuthenticationFailed.ToString() + "/ Steam authentication status changed: " + status.ToString());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (serverSettings.BanList.IsBanned(pendingClient.Connection.RemoteEndPoint.Address, steamID))
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.Banned.ToString() + "/ SteamID banned");
|
||||
return;
|
||||
}
|
||||
|
||||
if (status == ServerAuth.Status.OK)
|
||||
{
|
||||
pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password : ConnectionInitialization.Success;
|
||||
pendingClient.UpdateTime = Timing.TotalTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.SteamAuthenticationFailed.ToString() + "/ Steam authentication failed: " + status.ToString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Send(IWriteMessage msg, NetworkConnection conn, DeliveryMethod deliveryMethod)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
if (!(conn is LidgrenConnection lidgrenConn)) return;
|
||||
if (!connectedClients.Contains(lidgrenConn))
|
||||
{
|
||||
DebugConsole.ThrowError("Tried to send message to unauthenticated connection: " + lidgrenConn.IPString);
|
||||
return;
|
||||
}
|
||||
|
||||
NetDeliveryMethod lidgrenDeliveryMethod = NetDeliveryMethod.Unreliable;
|
||||
switch (deliveryMethod)
|
||||
{
|
||||
case DeliveryMethod.Unreliable:
|
||||
lidgrenDeliveryMethod = NetDeliveryMethod.Unreliable;
|
||||
break;
|
||||
case DeliveryMethod.Reliable:
|
||||
lidgrenDeliveryMethod = NetDeliveryMethod.ReliableUnordered;
|
||||
break;
|
||||
case DeliveryMethod.ReliableOrdered:
|
||||
lidgrenDeliveryMethod = NetDeliveryMethod.ReliableOrdered;
|
||||
break;
|
||||
}
|
||||
|
||||
NetOutgoingMessage lidgrenMsg = netServer.CreateMessage();
|
||||
byte[] msgData = new byte[msg.LengthBytes];
|
||||
msg.PrepareForSending(ref msgData, out bool isCompressed, out int length);
|
||||
lidgrenMsg.Write((byte)(isCompressed ? PacketHeader.IsCompressed : PacketHeader.None));
|
||||
lidgrenMsg.Write((UInt16)length);
|
||||
lidgrenMsg.Write(msgData, 0, length);
|
||||
|
||||
netServer.SendMessage(lidgrenMsg, lidgrenConn.NetConnection, lidgrenDeliveryMethod);
|
||||
}
|
||||
|
||||
public override void Disconnect(NetworkConnection conn,string msg=null)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
if (!(conn is LidgrenConnection lidgrenConn)) { return; }
|
||||
if (connectedClients.Contains(lidgrenConn))
|
||||
{
|
||||
lidgrenConn.Status = NetworkConnectionStatus.Disconnected;
|
||||
connectedClients.Remove(lidgrenConn);
|
||||
OnDisconnect?.Invoke(conn, msg);
|
||||
Steam.SteamManager.StopAuthSession(conn.SteamID);
|
||||
}
|
||||
lidgrenConn.NetConnection.Disconnect(msg ?? "Disconnected");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using Facepunch.Steamworks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
abstract class ServerPeer
|
||||
{
|
||||
public delegate void MessageCallback(NetworkConnection connection, IReadMessage message);
|
||||
public delegate void DisconnectCallback(NetworkConnection connection, string reason);
|
||||
public delegate void InitializationCompleteCallback(NetworkConnection connection);
|
||||
public delegate void ShutdownCallback();
|
||||
public delegate void OwnerDeterminedCallback(NetworkConnection connection);
|
||||
|
||||
public MessageCallback OnMessageReceived;
|
||||
public DisconnectCallback OnDisconnect;
|
||||
public InitializationCompleteCallback OnInitializationComplete;
|
||||
public ShutdownCallback OnShutdown;
|
||||
public OwnerDeterminedCallback OnOwnerDetermined;
|
||||
|
||||
protected int? ownerKey;
|
||||
|
||||
public NetworkConnection OwnerConnection { get; protected set; }
|
||||
|
||||
public abstract void InitializeSteamServerCallbacks(Facepunch.Steamworks.Server steamSrvr);
|
||||
|
||||
public abstract void Start();
|
||||
public abstract void Close(string msg = null);
|
||||
public abstract void Update(float deltaTime);
|
||||
public abstract void Send(IWriteMessage msg, NetworkConnection conn, DeliveryMethod deliveryMethod);
|
||||
public abstract void Disconnect(NetworkConnection conn, string msg = null);
|
||||
}
|
||||
}
|
||||
+652
@@ -0,0 +1,652 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Lidgren.Network;
|
||||
using Facepunch.Steamworks;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class SteamP2PServerPeer : ServerPeer
|
||||
{
|
||||
private ServerSettings serverSettings;
|
||||
|
||||
private NetPeerConfiguration netPeerConfiguration;
|
||||
private NetServer netServer;
|
||||
|
||||
private NetConnection netConnection;
|
||||
|
||||
public UInt64 OwnerSteamID
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
private class PendingClient
|
||||
{
|
||||
public string Name;
|
||||
public ConnectionInitialization InitializationStep;
|
||||
public double UpdateTime;
|
||||
public double TimeOut;
|
||||
public int Retries;
|
||||
public UInt64 SteamID;
|
||||
public Int32? PasswordSalt;
|
||||
public bool AuthSessionStarted;
|
||||
|
||||
public PendingClient(UInt64 steamId)
|
||||
{
|
||||
InitializationStep = ConnectionInitialization.SteamTicketAndVersion;
|
||||
Retries = 0;
|
||||
SteamID = steamId;
|
||||
PasswordSalt = null;
|
||||
UpdateTime = Timing.TotalTime;
|
||||
TimeOut = 20.0;
|
||||
AuthSessionStarted = false;
|
||||
}
|
||||
|
||||
public void Heartbeat()
|
||||
{
|
||||
TimeOut = 5.0;
|
||||
}
|
||||
}
|
||||
|
||||
private List<SteamP2PConnection> connectedClients;
|
||||
private List<PendingClient> pendingClients;
|
||||
|
||||
private List<NetIncomingMessage> incomingLidgrenMessages;
|
||||
|
||||
public SteamP2PServerPeer(UInt64 steamId, ServerSettings settings)
|
||||
{
|
||||
serverSettings = settings;
|
||||
|
||||
netServer = null;
|
||||
|
||||
connectedClients = new List<SteamP2PConnection>();
|
||||
pendingClients = new List<PendingClient>();
|
||||
|
||||
incomingLidgrenMessages = new List<NetIncomingMessage>();
|
||||
|
||||
ownerKey = null;
|
||||
|
||||
OwnerSteamID = steamId;
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
if (netServer != null) { return; }
|
||||
|
||||
netPeerConfiguration = new NetPeerConfiguration("barotrauma")
|
||||
{
|
||||
AcceptIncomingConnections = true,
|
||||
AutoExpandMTU = false,
|
||||
MaximumConnections = 1, //only allow owner to connect
|
||||
EnableUPnP = false,
|
||||
Port = Steam.SteamManager.STEAMP2P_OWNER_PORT
|
||||
};
|
||||
|
||||
netPeerConfiguration.DisableMessageType(NetIncomingMessageType.DebugMessage |
|
||||
NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt |
|
||||
NetIncomingMessageType.ErrorMessage | NetIncomingMessageType.Error |
|
||||
NetIncomingMessageType.UnconnectedData);
|
||||
|
||||
netPeerConfiguration.EnableMessageType(NetIncomingMessageType.ConnectionApproval);
|
||||
|
||||
netServer = new NetServer(netPeerConfiguration);
|
||||
|
||||
netServer.Start();
|
||||
}
|
||||
|
||||
public override void Close(string msg = null)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
if (OwnerConnection != null) OwnerConnection.Status = NetworkConnectionStatus.Disconnected;
|
||||
|
||||
for (int i = pendingClients.Count - 1; i >= 0; i--)
|
||||
{
|
||||
RemovePendingClient(pendingClients[i], msg ?? DisconnectReason.ServerShutdown.ToString());
|
||||
}
|
||||
|
||||
for (int i = connectedClients.Count - 1; i >= 0; i--)
|
||||
{
|
||||
Disconnect(connectedClients[i], msg ?? DisconnectReason.ServerShutdown.ToString());
|
||||
}
|
||||
|
||||
netServer.Shutdown(msg ?? DisconnectReason.ServerShutdown.ToString());
|
||||
|
||||
pendingClients.Clear();
|
||||
connectedClients.Clear();
|
||||
|
||||
netServer = null;
|
||||
|
||||
OnShutdown?.Invoke();
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
if (OnOwnerDetermined != null && OwnerConnection != null)
|
||||
{
|
||||
OnOwnerDetermined?.Invoke(OwnerConnection);
|
||||
OnOwnerDetermined = null;
|
||||
}
|
||||
|
||||
netServer.ReadMessages(incomingLidgrenMessages);
|
||||
|
||||
//backwards for loop so we can remove elements while iterating
|
||||
for (int i = connectedClients.Count - 1; i >= 0; i--)
|
||||
{
|
||||
connectedClients[i].Decay(deltaTime);
|
||||
if (connectedClients[i].Timeout < 0.0)
|
||||
{
|
||||
Disconnect(connectedClients[i], "Timed out");
|
||||
}
|
||||
}
|
||||
|
||||
//process incoming connections first
|
||||
foreach (NetIncomingMessage inc in incomingLidgrenMessages.Where(m => m.MessageType == NetIncomingMessageType.ConnectionApproval))
|
||||
{
|
||||
HandleConnection(inc);
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
//after processing connections, go ahead with the rest of the messages
|
||||
foreach (NetIncomingMessage inc in incomingLidgrenMessages.Where(m => m.MessageType != NetIncomingMessageType.ConnectionApproval))
|
||||
{
|
||||
switch (inc.MessageType)
|
||||
{
|
||||
case NetIncomingMessageType.Data:
|
||||
HandleDataMessage(inc);
|
||||
break;
|
||||
case NetIncomingMessageType.StatusChanged:
|
||||
HandleStatusChanged(inc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
string errorMsg = "Server failed to read an incoming message. {" + e + "}\n" + e.StackTrace;
|
||||
GameAnalyticsManager.AddErrorEventOnce("SteamP2PServerPeer.Update:ClientReadException" + e.TargetSite.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
#else
|
||||
if (GameSettings.VerboseLogging) { DebugConsole.ThrowError(errorMsg); }
|
||||
#endif
|
||||
}
|
||||
|
||||
for (int i = 0; i < pendingClients.Count; i++)
|
||||
{
|
||||
PendingClient pendingClient = pendingClients[i];
|
||||
UpdatePendingClient(pendingClient);
|
||||
if (i >= pendingClients.Count || pendingClients[i] != pendingClient) { i--; }
|
||||
}
|
||||
|
||||
incomingLidgrenMessages.Clear();
|
||||
}
|
||||
|
||||
private void HandleConnection(NetIncomingMessage inc)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
if (netConnection != null && inc.SenderConnection != netConnection)
|
||||
{
|
||||
inc.SenderConnection.Deny(DisconnectReason.SessionTaken.ToString()+"/ Owner is already connected");
|
||||
return;
|
||||
}
|
||||
|
||||
if (IPAddress.IsLoopback(inc.SenderConnection.RemoteEndPoint.Address.MapToIPv4()))
|
||||
{
|
||||
inc.SenderConnection.Approve();
|
||||
netConnection = inc.SenderConnection;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
inc.SenderConnection.Deny(DisconnectReason.Kicked.ToString()+"/ Incoming connection is not loopback");
|
||||
}
|
||||
|
||||
private void HandleDataMessage(NetIncomingMessage inc)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
if (inc.SenderConnection != netConnection) { return; }
|
||||
|
||||
UInt64 senderSteamId = inc.ReadUInt64();
|
||||
|
||||
byte incByte = inc.ReadByte();
|
||||
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
|
||||
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
|
||||
bool isDisconnectMessage = (incByte & (byte)PacketHeader.IsDisconnectMessage) != 0;
|
||||
bool isServerMessage = (incByte & (byte)PacketHeader.IsServerMessage) != 0;
|
||||
bool isHeartbeatMessage = (incByte & (byte)PacketHeader.IsHeartbeatMessage) != 0;
|
||||
|
||||
if (isServerMessage)
|
||||
{
|
||||
DebugConsole.ThrowError("got server message from" + senderSteamId.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (senderSteamId != OwnerSteamID) //sender is remote, handle disconnects and heartbeats
|
||||
{
|
||||
PendingClient pendingClient = pendingClients.Find(c => c.SteamID == senderSteamId);
|
||||
SteamP2PConnection connectedClient = connectedClients.Find(c => c.SteamID == senderSteamId);
|
||||
|
||||
pendingClient?.Heartbeat();
|
||||
connectedClient?.Heartbeat();
|
||||
|
||||
if (serverSettings.BanList.IsBanned(senderSteamId))
|
||||
{
|
||||
if (pendingClient != null)
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.Banned.ToString()+"/ Banned");
|
||||
}
|
||||
else if (connectedClient != null)
|
||||
{
|
||||
Disconnect(connectedClient, DisconnectReason.Banned.ToString() + "/ Banned");
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (isDisconnectMessage)
|
||||
{
|
||||
if (pendingClient != null)
|
||||
{
|
||||
string disconnectMsg = $"ServerMessage.HasDisconnected~[client]={pendingClient.Name}";
|
||||
RemovePendingClient(pendingClient, disconnectMsg);
|
||||
}
|
||||
else if (connectedClient != null)
|
||||
{
|
||||
string disconnectMsg = $"ServerMessage.HasDisconnected~[client]={connectedClient.Name}";
|
||||
Disconnect(connectedClient, disconnectMsg, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (isHeartbeatMessage)
|
||||
{
|
||||
//message exists solely as a heartbeat, ignore its contents
|
||||
return;
|
||||
}
|
||||
else if (isConnectionInitializationStep)
|
||||
{
|
||||
if (pendingClient != null)
|
||||
{
|
||||
ReadConnectionInitializationStep(pendingClient, new ReadOnlyMessage(inc.Data, false, inc.PositionInBytes, inc.LengthBytes - inc.PositionInBytes, null));
|
||||
}
|
||||
else
|
||||
{
|
||||
ConnectionInitialization initializationStep = (ConnectionInitialization)inc.ReadByte();
|
||||
if (initializationStep == ConnectionInitialization.ConnectionStarted)
|
||||
{
|
||||
pendingClients.Add(new PendingClient(senderSteamId));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (connectedClient != null)
|
||||
{
|
||||
UInt16 length = inc.ReadUInt16();
|
||||
|
||||
IReadMessage msg = new ReadOnlyMessage(inc.Data, isCompressed, inc.PositionInBytes, length, connectedClient);
|
||||
OnMessageReceived?.Invoke(connectedClient, msg);
|
||||
}
|
||||
}
|
||||
else //sender is owner
|
||||
{
|
||||
if (OwnerConnection != null) { (OwnerConnection as SteamP2PConnection).Heartbeat(); }
|
||||
|
||||
if (isDisconnectMessage)
|
||||
{
|
||||
DebugConsole.ThrowError("Received disconnect message from owner");
|
||||
return;
|
||||
}
|
||||
if (isServerMessage)
|
||||
{
|
||||
DebugConsole.ThrowError("Received server message from owner");
|
||||
return;
|
||||
}
|
||||
if (isConnectionInitializationStep)
|
||||
{
|
||||
if (OwnerConnection == null)
|
||||
{
|
||||
string ownerName = inc.ReadString();
|
||||
OwnerConnection = new SteamP2PConnection(ownerName, OwnerSteamID);
|
||||
OwnerConnection.Status = NetworkConnectionStatus.Connected;
|
||||
|
||||
OnInitializationComplete?.Invoke(OwnerConnection);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (isHeartbeatMessage)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt16 length = inc.ReadUInt16();
|
||||
|
||||
IReadMessage msg = new ReadOnlyMessage(inc.Data, isCompressed, inc.PositionInBytes, length, OwnerConnection);
|
||||
OnMessageReceived?.Invoke(OwnerConnection, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleStatusChanged(NetIncomingMessage inc)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
DebugConsole.NewMessage(inc.SenderConnection.Status.ToString());
|
||||
|
||||
switch (inc.SenderConnection.Status)
|
||||
{
|
||||
case NetConnectionStatus.Connected:
|
||||
NetOutgoingMessage outMsg = netServer.CreateMessage();
|
||||
outMsg.Write(OwnerSteamID);
|
||||
outMsg.Write((byte)(PacketHeader.IsConnectionInitializationStep | PacketHeader.IsServerMessage));
|
||||
netServer.SendMessage(outMsg, netConnection, NetDeliveryMethod.ReliableUnordered);
|
||||
break;
|
||||
case NetConnectionStatus.Disconnected:
|
||||
DebugConsole.NewMessage("Owner disconnected: closing the server...");
|
||||
GameServer.Log("Owner disconnected: closing the server...", ServerLog.MessageType.ServerMessage);
|
||||
Close(DisconnectReason.ServerShutdown.ToString() + "/ Owner disconnected");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadConnectionInitializationStep(PendingClient pendingClient, IReadMessage inc)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
pendingClient.TimeOut = 20.0;
|
||||
|
||||
ConnectionInitialization initializationStep = (ConnectionInitialization)inc.ReadByte();
|
||||
|
||||
//DebugConsole.NewMessage(initializationStep+" "+pendingClient.InitializationStep);
|
||||
|
||||
if (pendingClient.InitializationStep != initializationStep) return;
|
||||
|
||||
switch (initializationStep)
|
||||
{
|
||||
case ConnectionInitialization.SteamTicketAndVersion:
|
||||
string name = Client.SanitizeName(inc.ReadString());
|
||||
UInt64 steamId = inc.ReadUInt64();
|
||||
UInt16 ticketLength = inc.ReadUInt16();
|
||||
inc.BitPosition += ticketLength * 8; //skip ticket, owner handles steam authentication
|
||||
|
||||
if (!Client.IsValidName(name, serverSettings))
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.InvalidName.ToString() + "/ The name \"" + name + "\" is invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
string version = inc.ReadString();
|
||||
bool isCompatibleVersion = NetworkMember.IsCompatible(version, GameMain.Version.ToString()) ?? false;
|
||||
if (!isCompatibleVersion)
|
||||
{
|
||||
RemovePendingClient(pendingClient,
|
||||
$"DisconnectMessage.InvalidVersion~[version]={GameMain.Version.ToString()}~[clientversion]={version}");
|
||||
|
||||
GameServer.Log(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (incompatible game version)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (incompatible game version)", Microsoft.Xna.Framework.Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
int contentPackageCount = (int)inc.ReadVariableUInt32();
|
||||
List<ClientContentPackage> contentPackages = new List<ClientContentPackage>();
|
||||
for (int i = 0; i < contentPackageCount; i++)
|
||||
{
|
||||
string packageName = inc.ReadString();
|
||||
string packageHash = inc.ReadString();
|
||||
contentPackages.Add(new ClientContentPackage(packageName, packageHash));
|
||||
}
|
||||
|
||||
List<ContentPackage> missingPackages = new List<ContentPackage>();
|
||||
foreach (ContentPackage contentPackage in GameMain.SelectedPackages)
|
||||
{
|
||||
if (!contentPackage.HasMultiplayerIncompatibleContent) continue;
|
||||
bool packageFound = false;
|
||||
for (int i = 0; i < (int)contentPackageCount; i++)
|
||||
{
|
||||
if (contentPackages[i].Name == contentPackage.Name && contentPackages[i].Hash == contentPackage.MD5hash.Hash)
|
||||
{
|
||||
packageFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!packageFound) missingPackages.Add(contentPackage);
|
||||
}
|
||||
|
||||
if (missingPackages.Count == 1)
|
||||
{
|
||||
RemovePendingClient(pendingClient,
|
||||
$"DisconnectMessage.MissingContentPackage~[missingcontentpackage]={GetPackageStr(missingPackages[0])}");
|
||||
GameServer.Log(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (missing content package " + GetPackageStr(missingPackages[0]) + ")", ServerLog.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
else if (missingPackages.Count > 1)
|
||||
{
|
||||
List<string> packageStrs = new List<string>();
|
||||
missingPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
|
||||
RemovePendingClient(pendingClient,
|
||||
$"DisconnectMessage.MissingContentPackages~[missingcontentpackages]={string.Join(", ", packageStrs)}");
|
||||
GameServer.Log(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (missing content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pendingClient.AuthSessionStarted)
|
||||
{
|
||||
pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password: ConnectionInitialization.Success;
|
||||
|
||||
pendingClient.Name = name;
|
||||
pendingClient.AuthSessionStarted = true;
|
||||
}
|
||||
break;
|
||||
case ConnectionInitialization.Password:
|
||||
int pwLength = inc.ReadByte();
|
||||
byte[] incPassword = inc.ReadBytes(pwLength);
|
||||
if (pendingClient.PasswordSalt == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Received password message from client without salt");
|
||||
return;
|
||||
}
|
||||
if (serverSettings.IsPasswordCorrect(incPassword, pendingClient.PasswordSalt.Value))
|
||||
{
|
||||
pendingClient.InitializationStep = ConnectionInitialization.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
pendingClient.Retries++;
|
||||
|
||||
if (pendingClient.Retries >= 3)
|
||||
{
|
||||
string banMsg = "Failed to enter correct password too many times";
|
||||
serverSettings.BanList.BanPlayer(pendingClient.Name, pendingClient.SteamID, banMsg, null);
|
||||
|
||||
RemovePendingClient(pendingClient, DisconnectReason.Banned.ToString()+"/ "+banMsg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
pendingClient.UpdateTime = Timing.TotalTime;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected struct ClientContentPackage
|
||||
{
|
||||
public string Name;
|
||||
public string Hash;
|
||||
|
||||
public ClientContentPackage(string name, string hash)
|
||||
{
|
||||
Name = name; Hash = hash;
|
||||
}
|
||||
}
|
||||
|
||||
private string GetPackageStr(ContentPackage contentPackage)
|
||||
{
|
||||
return "\"" + contentPackage.Name + "\" (hash " + contentPackage.MD5hash.ShortHash + ")";
|
||||
}
|
||||
|
||||
private void UpdatePendingClient(PendingClient pendingClient)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
if (serverSettings.BanList.IsBanned(pendingClient.SteamID))
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.Banned.ToString()+"/ Initialization interrupted by ban");
|
||||
return;
|
||||
}
|
||||
|
||||
//DebugConsole.NewMessage("pending client status: " + pendingClient.InitializationStep);
|
||||
|
||||
if (connectedClients.Count >= serverSettings.MaxPlayers-1)
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.ServerFull.ToString());
|
||||
}
|
||||
|
||||
if (pendingClient.InitializationStep == ConnectionInitialization.Success)
|
||||
{
|
||||
SteamP2PConnection newConnection = new SteamP2PConnection(pendingClient.Name, pendingClient.SteamID);
|
||||
newConnection.Status = NetworkConnectionStatus.Connected;
|
||||
connectedClients.Add(newConnection);
|
||||
pendingClients.Remove(pendingClient);
|
||||
OnInitializationComplete?.Invoke(newConnection);
|
||||
}
|
||||
|
||||
pendingClient.TimeOut -= Timing.Step;
|
||||
if (pendingClient.TimeOut < 0.0)
|
||||
{
|
||||
RemovePendingClient(pendingClient, Lidgren.Network.NetConnection.NoResponseMessage);
|
||||
}
|
||||
|
||||
if (Timing.TotalTime < pendingClient.UpdateTime) { return; }
|
||||
pendingClient.UpdateTime = Timing.TotalTime + 1.0;
|
||||
|
||||
NetOutgoingMessage outMsg = netServer.CreateMessage();
|
||||
outMsg.Write(pendingClient.SteamID);
|
||||
outMsg.Write((byte)(PacketHeader.IsConnectionInitializationStep |
|
||||
PacketHeader.IsServerMessage));
|
||||
outMsg.Write((byte)pendingClient.InitializationStep);
|
||||
switch (pendingClient.InitializationStep)
|
||||
{
|
||||
case ConnectionInitialization.Password:
|
||||
outMsg.Write(pendingClient.PasswordSalt == null); outMsg.WritePadBits();
|
||||
if (pendingClient.PasswordSalt == null)
|
||||
{
|
||||
pendingClient.PasswordSalt = CryptoRandom.Instance.Next();
|
||||
outMsg.Write(pendingClient.PasswordSalt.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
outMsg.Write(pendingClient.Retries);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (netConnection != null)
|
||||
{
|
||||
NetSendResult result = netServer.SendMessage(outMsg, netConnection, NetDeliveryMethod.ReliableUnordered);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemovePendingClient(PendingClient pendingClient, string reason)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
if (pendingClients.Contains(pendingClient))
|
||||
{
|
||||
SendDisconnectMessage(pendingClient.SteamID, reason);
|
||||
|
||||
pendingClients.Remove(pendingClient);
|
||||
|
||||
if (pendingClient.AuthSessionStarted)
|
||||
{
|
||||
Steam.SteamManager.StopAuthSession(pendingClient.SteamID);
|
||||
pendingClient.SteamID = 0;
|
||||
pendingClient.AuthSessionStarted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void InitializeSteamServerCallbacks(Server steamSrvr)
|
||||
{
|
||||
throw new InvalidOperationException("Called InitializeSteamServerCallbacks on SteamP2PServerPeer!");
|
||||
}
|
||||
|
||||
public override void Send(IWriteMessage msg, NetworkConnection conn, DeliveryMethod deliveryMethod)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
if (!(conn is SteamP2PConnection steamp2pConn)) return;
|
||||
if (!connectedClients.Contains(steamp2pConn) && conn != OwnerConnection)
|
||||
{
|
||||
DebugConsole.ThrowError("Tried to send message to unauthenticated connection: " + steamp2pConn.SteamID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
NetDeliveryMethod lidgrenDeliveryMethod = NetDeliveryMethod.Unreliable;
|
||||
switch (deliveryMethod)
|
||||
{
|
||||
case DeliveryMethod.Unreliable:
|
||||
lidgrenDeliveryMethod = NetDeliveryMethod.Unreliable;
|
||||
break;
|
||||
case DeliveryMethod.Reliable:
|
||||
lidgrenDeliveryMethod = NetDeliveryMethod.ReliableUnordered;
|
||||
break;
|
||||
case DeliveryMethod.ReliableOrdered:
|
||||
lidgrenDeliveryMethod = NetDeliveryMethod.ReliableOrdered;
|
||||
break;
|
||||
}
|
||||
|
||||
NetOutgoingMessage lidgrenMsg = netServer.CreateMessage();
|
||||
byte[] msgData = new byte[1500];
|
||||
msg.PrepareForSending(ref msgData, out bool isCompressed, out int length);
|
||||
lidgrenMsg.Write(conn.SteamID);
|
||||
lidgrenMsg.Write((byte)((isCompressed ? PacketHeader.IsCompressed : PacketHeader.None) | PacketHeader.IsServerMessage));
|
||||
lidgrenMsg.Write((UInt16)length);
|
||||
lidgrenMsg.Write(msgData, 0, length);
|
||||
|
||||
netServer.SendMessage(lidgrenMsg, netConnection, lidgrenDeliveryMethod);
|
||||
}
|
||||
|
||||
private void SendDisconnectMessage(UInt64 steamId, string msg)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
if (string.IsNullOrWhiteSpace(msg)) { return; }
|
||||
|
||||
NetOutgoingMessage lidgrenMsg = netServer.CreateMessage();
|
||||
lidgrenMsg.Write(steamId);
|
||||
lidgrenMsg.Write((byte)(PacketHeader.IsDisconnectMessage | PacketHeader.IsServerMessage));
|
||||
lidgrenMsg.Write(msg);
|
||||
|
||||
netServer.SendMessage(lidgrenMsg, netConnection, NetDeliveryMethod.ReliableUnordered);
|
||||
}
|
||||
|
||||
private void Disconnect(NetworkConnection conn, string msg, bool sendDisconnectMessage)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
if (!(conn is SteamP2PConnection steamp2pConn)) { return; }
|
||||
if (connectedClients.Contains(steamp2pConn))
|
||||
{
|
||||
if (sendDisconnectMessage) SendDisconnectMessage(steamp2pConn.SteamID, msg);
|
||||
steamp2pConn.Status = NetworkConnectionStatus.Disconnected;
|
||||
connectedClients.Remove(steamp2pConn);
|
||||
OnDisconnect?.Invoke(conn, msg);
|
||||
Steam.SteamManager.StopAuthSession(conn.SteamID);
|
||||
}
|
||||
else if (steamp2pConn == OwnerConnection)
|
||||
{
|
||||
netConnection.Disconnect(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Disconnect(NetworkConnection conn, string msg = null)
|
||||
{
|
||||
Disconnect(conn, msg, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,8 +27,8 @@ namespace Barotrauma.Networking
|
||||
.ToList();
|
||||
}
|
||||
|
||||
int currPlayerCount = GameMain.Server.ConnectedClients.Count(c =>
|
||||
c.InGame &&
|
||||
int currPlayerCount = GameMain.Server.ConnectedClients.Count(c =>
|
||||
c.InGame &&
|
||||
(!c.SpectateOnly || (!GameMain.Server.ServerSettings.AllowSpectating && GameMain.Server.OwnerConnection != c.Connection)));
|
||||
|
||||
var existingBots = Character.CharacterList
|
||||
@@ -68,7 +68,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
RespawnCountdownStarted = respawnPending;
|
||||
RespawnTime = DateTime.Now + new TimeSpan(0,0,0,0, (int)(GameMain.Server.ServerSettings.RespawnInterval * 1000.0f));
|
||||
GameMain.Server.CreateEntityEvent(this);
|
||||
GameMain.Server.CreateEntityEvent(this);
|
||||
}
|
||||
|
||||
if (!RespawnCountdownStarted) { return; }
|
||||
@@ -180,7 +180,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
partial void UpdateTransportingProjSpecific(float deltaTime)
|
||||
{
|
||||
|
||||
|
||||
if (!ReturnCountdownStarted)
|
||||
{
|
||||
//if there are no living chracters inside, transporting can be stopped immediately
|
||||
@@ -231,7 +231,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
var botsToSpawn = GetBotsToRespawn();
|
||||
characterInfos.AddRange(botsToSpawn);
|
||||
|
||||
|
||||
GameMain.Server.AssignJobs(clients);
|
||||
foreach (Client c in clients)
|
||||
{
|
||||
@@ -257,7 +257,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
var character = Character.Create(characterInfos[i], shuttleSpawnPoints[i].WorldPosition, characterInfos[i].Name, !bot, bot);
|
||||
character.TeamID = Character.TeamType.Team1;
|
||||
|
||||
|
||||
if (bot)
|
||||
{
|
||||
GameServer.Log(string.Format("Respawning bot {0} as {1}", character.Info.Name, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning);
|
||||
@@ -265,18 +265,18 @@ namespace Barotrauma.Networking
|
||||
else
|
||||
{
|
||||
//tell the respawning client they're no longer a traitor
|
||||
if (GameMain.Server.TraitorManager != null && clients[i].Character != null)
|
||||
if (GameMain.Server.TraitorManager?.Traitors != null && clients[i].Character != null)
|
||||
{
|
||||
if (GameMain.Server.TraitorManager.TraitorList.Any(t => t.Character == clients[i].Character))
|
||||
if (GameMain.Server.TraitorManager.Traitors.Any(t => t.Character == clients[i].Character))
|
||||
{
|
||||
GameMain.Server.SendDirectChatMessage(TextManager.Get("traitorrespawnmessage"), clients[i], ChatMessageType.MessageBox);
|
||||
GameMain.Server.SendDirectChatMessage(TextManager.FormatServerMessage("TraitorRespawnMessage"), clients[i], ChatMessageType.ServerMessageBox);
|
||||
}
|
||||
}
|
||||
|
||||
clients[i].Character = character;
|
||||
character.OwnerClientIP = clients[i].Connection.RemoteEndPoint.Address.ToString();
|
||||
character.OwnerClientEndPoint = clients[i].Connection.EndPointString;
|
||||
character.OwnerClientName = clients[i].Name;
|
||||
GameServer.Log(string.Format("Respawning {0} ({1}) as {2}", clients[i].Name, clients[i].Connection?.RemoteEndPoint?.Address, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning);
|
||||
GameServer.Log(string.Format("Respawning {0} ({1}) as {2}", clients[i].Name, clients[i].Connection?.EndPointString, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning);
|
||||
}
|
||||
|
||||
if (divingSuitPrefab != null && oxyPrefab != null && RespawnShuttle != null)
|
||||
@@ -325,9 +325,9 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
msg.WriteRangedInteger(0, Enum.GetNames(typeof(State)).Length, (int)CurrentState);
|
||||
msg.WriteRangedIntegerDeprecated(0, Enum.GetNames(typeof(State)).Length, (int)CurrentState);
|
||||
|
||||
switch (CurrentState)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
@@ -20,7 +19,7 @@ namespace Barotrauma.Networking
|
||||
LoadClientPermissions();
|
||||
}
|
||||
|
||||
private void WriteNetProperties(NetBuffer outMsg)
|
||||
private void WriteNetProperties(IWriteMessage outMsg)
|
||||
{
|
||||
outMsg.Write((UInt16)netProperties.Keys.Count);
|
||||
foreach (UInt32 key in netProperties.Keys)
|
||||
@@ -30,7 +29,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerAdminWrite(NetBuffer outMsg, Client c)
|
||||
public void ServerAdminWrite(IWriteMessage outMsg, Client c)
|
||||
{
|
||||
//outMsg.Write(isPublic);
|
||||
//outMsg.Write(EnableUPnP);
|
||||
@@ -43,11 +42,15 @@ namespace Barotrauma.Networking
|
||||
Whitelist.ServerAdminWrite(outMsg, c);
|
||||
}
|
||||
|
||||
public void ServerWrite(NetBuffer outMsg,Client c)
|
||||
public void ServerWrite(IWriteMessage outMsg,Client c)
|
||||
{
|
||||
outMsg.Write(ServerName);
|
||||
outMsg.Write(ServerMessageText);
|
||||
outMsg.WriteRangedInteger(1, 60, TickRate);
|
||||
outMsg.Write((byte)MaxPlayers);
|
||||
outMsg.Write(HasPassword);
|
||||
outMsg.Write(isPublic);
|
||||
outMsg.WritePadBits();
|
||||
outMsg.WriteRangedIntegerDeprecated(1, 60, TickRate);
|
||||
|
||||
WriteExtraCargo(outMsg);
|
||||
|
||||
@@ -67,7 +70,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerRead(NetIncomingMessage incMsg,Client c)
|
||||
public void ServerRead(IReadMessage incMsg,Client c)
|
||||
{
|
||||
if (!c.HasPermission(Networking.ClientPermissions.ManageSettings)) return;
|
||||
|
||||
@@ -112,7 +115,7 @@ namespace Barotrauma.Networking
|
||||
else
|
||||
{
|
||||
UInt32 size = incMsg.ReadVariableUInt32();
|
||||
incMsg.Position += 8 * size;
|
||||
incMsg.BitPosition += (int)(8 * size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +148,7 @@ namespace Barotrauma.Networking
|
||||
if (botSpawnMode > 1) botSpawnMode = 0;
|
||||
BotSpawnMode = (BotSpawnMode)botSpawnMode;
|
||||
|
||||
float levelDifficulty = incMsg.ReadFloat();
|
||||
float levelDifficulty = incMsg.ReadSingle();
|
||||
if (levelDifficulty >= 0.0f) SelectedLevelDifficulty = levelDifficulty;
|
||||
|
||||
UseRespawnShuttle = incMsg.ReadBoolean();
|
||||
@@ -177,24 +180,16 @@ namespace Barotrauma.Networking
|
||||
|
||||
doc.Root.SetAttributeValue("name", ServerName);
|
||||
doc.Root.SetAttributeValue("public", isPublic);
|
||||
doc.Root.SetAttributeValue("port", GameMain.Server.NetPeerConfiguration.Port);
|
||||
doc.Root.SetAttributeValue("port", Port);
|
||||
if (Steam.SteamManager.USE_STEAM) doc.Root.SetAttributeValue("queryport", QueryPort);
|
||||
doc.Root.SetAttributeValue("maxplayers", maxPlayers);
|
||||
doc.Root.SetAttributeValue("enableupnp", GameMain.Server.NetPeerConfiguration.EnableUPnP);
|
||||
doc.Root.SetAttributeValue("enableupnp", EnableUPnP);
|
||||
|
||||
doc.Root.SetAttributeValue("autorestart", autoRestart);
|
||||
|
||||
doc.Root.SetAttributeValue("SubSelection", SubSelectionMode.ToString());
|
||||
doc.Root.SetAttributeValue("ModeSelection", ModeSelectionMode.ToString());
|
||||
|
||||
doc.Root.SetAttributeValue("LevelDifficulty", ((int)selectedLevelDifficulty).ToString());
|
||||
doc.Root.SetAttributeValue("TraitorsEnabled", TraitorsEnabled.ToString());
|
||||
|
||||
/*doc.Root.SetAttributeValue("BotCount", BotCount);
|
||||
doc.Root.SetAttributeValue("MaxBotCount", MaxBotCount);*/
|
||||
doc.Root.SetAttributeValue("BotSpawnMode", BotSpawnMode.ToString());
|
||||
|
||||
|
||||
doc.Root.SetAttributeValue("AllowedRandomMissionTypes", string.Join(",", AllowedRandomMissionTypes));
|
||||
|
||||
doc.Root.SetAttributeValue("AllowedClientNameChars", string.Join(",", AllowedClientNameChars.Select(c => c.First + "-" + c.Second)));
|
||||
|
||||
doc.Root.SetAttributeValue("ServerMessage", ServerMessageText);
|
||||
@@ -239,18 +234,22 @@ namespace Barotrauma.Networking
|
||||
|
||||
selectedLevelDifficulty = doc.Root.GetAttributeFloat("LevelDifficulty", 20.0f);
|
||||
GameMain.NetLobbyScreen.SetLevelDifficulty(selectedLevelDifficulty);
|
||||
|
||||
var traitorsEnabled = TraitorsEnabled;
|
||||
Enum.TryParse(doc.Root.GetAttributeString("TraitorsEnabled", "No"), out traitorsEnabled);
|
||||
TraitorsEnabled = traitorsEnabled;
|
||||
|
||||
GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled);
|
||||
|
||||
var botSpawnMode = BotSpawnMode.Normal;
|
||||
Enum.TryParse(doc.Root.GetAttributeString("BotSpawnMode", "Normal"), out botSpawnMode);
|
||||
BotSpawnMode = botSpawnMode;
|
||||
|
||||
//"65-90", "97-122", "48-59" = upper and lower case english alphabet and numbers
|
||||
string[] allowedClientNameCharsStr = doc.Root.GetAttributeStringArray("AllowedClientNameChars", new string[] { "65-90", "97-122", "48-59" });
|
||||
|
||||
string[] allowedClientNameCharsStr = doc.Root.GetAttributeStringArray("AllowedClientNameChars",
|
||||
new string[] {
|
||||
"32-33",
|
||||
"38-46",
|
||||
"48-57",
|
||||
"65-90",
|
||||
"91",
|
||||
"93",
|
||||
"95-122",
|
||||
"192-255",
|
||||
"384-591",
|
||||
"1024-1279"
|
||||
});
|
||||
foreach (string allowedClientNameCharRange in allowedClientNameCharsStr)
|
||||
{
|
||||
string[] splitRange = allowedClientNameCharRange.Split('-');
|
||||
@@ -329,7 +328,7 @@ namespace Barotrauma.Networking
|
||||
foreach (XElement clientElement in doc.Root.Elements())
|
||||
{
|
||||
string clientName = clientElement.GetAttributeString("name", "");
|
||||
string clientIP = clientElement.GetAttributeString("ip", "");
|
||||
string clientEndPoint = clientElement.GetAttributeString("endpoint", null) ?? clientElement.GetAttributeString("ip", "");
|
||||
string steamIdStr = clientElement.GetAttributeString("steamid", "");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(clientName))
|
||||
@@ -337,7 +336,7 @@ namespace Barotrauma.Networking
|
||||
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - all clients must have a name and an IP address.");
|
||||
continue;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(clientIP) && string.IsNullOrWhiteSpace(steamIdStr))
|
||||
if (string.IsNullOrWhiteSpace(clientEndPoint) && string.IsNullOrWhiteSpace(steamIdStr))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - all clients must have an IP address or a Steam ID.");
|
||||
continue;
|
||||
@@ -410,7 +409,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else
|
||||
{
|
||||
ClientPermissions.Add(new SavedClientPermission(clientName, clientIP, permissions, permittedCommands));
|
||||
ClientPermissions.Add(new SavedClientPermission(clientName, clientEndPoint, permissions, permittedCommands));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -480,7 +479,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else
|
||||
{
|
||||
clientElement.Add(new XAttribute("ip", clientPermission.IP));
|
||||
clientElement.Add(new XAttribute("endpoint", clientPermission.EndPoint));
|
||||
}
|
||||
|
||||
if (matchingPreset == null)
|
||||
|
||||
@@ -29,7 +29,8 @@ namespace Barotrauma.Steam
|
||||
|
||||
RefreshServerDetails(server);
|
||||
|
||||
instance.server.Auth.OnAuthChange = server.OnAuthChange;
|
||||
server.ServerPeer.InitializeSteamServerCallbacks(instance.server);
|
||||
|
||||
Instance.server.LogOnAnonymous();
|
||||
|
||||
return true;
|
||||
@@ -66,23 +67,24 @@ namespace Barotrauma.Steam
|
||||
Instance.server.SetKey("traitors", server.ServerSettings.TraitorsEnabled.ToString());
|
||||
Instance.server.SetKey("gamestarted", server.GameStarted.ToString());
|
||||
Instance.server.SetKey("gamemode", server.ServerSettings.GameModeIdentifier);
|
||||
|
||||
|
||||
instance.server.DedicatedServer = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool StartAuthSession(byte[] authTicketData, ulong clientSteamID)
|
||||
public static ServerAuth.StartAuthSessionResult StartAuthSession(byte[] authTicketData, ulong clientSteamID)
|
||||
{
|
||||
if (instance == null || !instance.isInitialized || instance.server == null) return false;
|
||||
|
||||
if (instance == null || !instance.isInitialized || instance.server == null) return ServerAuth.StartAuthSessionResult.ServerNotConnectedToSteam;
|
||||
|
||||
DebugConsole.Log("SteamManager authenticating Steam client " + clientSteamID);
|
||||
if (!instance.server.Auth.StartSession(authTicketData, clientSteamID))
|
||||
ServerAuth.StartAuthSessionResult startResult = instance.server.Auth.StartSession(authTicketData, clientSteamID);
|
||||
if (startResult != ServerAuth.StartAuthSessionResult.OK)
|
||||
{
|
||||
DebugConsole.Log("Authentication failed");
|
||||
return false;
|
||||
DebugConsole.Log("Authentication failed: failed to start auth session (" + startResult.ToString() + ")");
|
||||
}
|
||||
return true;
|
||||
|
||||
return startResult;
|
||||
}
|
||||
|
||||
public static void StopAuthSession(ulong clientSteamID)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -9,11 +8,11 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
class VoipServer
|
||||
{
|
||||
private NetServer netServer;
|
||||
private ServerPeer netServer;
|
||||
private List<VoipQueue> queues;
|
||||
private Dictionary<VoipQueue,DateTime> lastSendTime;
|
||||
|
||||
public VoipServer(NetServer server)
|
||||
public VoipServer(ServerPeer server)
|
||||
{
|
||||
this.netServer = server;
|
||||
queues = new List<VoipQueue>();
|
||||
@@ -54,15 +53,13 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (!CanReceive(sender, recipient)) { continue; }
|
||||
|
||||
NetOutgoingMessage msg = netServer.CreateMessage();
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
|
||||
msg.Write((byte)ServerPacketHeader.VOICE);
|
||||
msg.Write((byte)queue.QueueID);
|
||||
queue.Write(msg);
|
||||
|
||||
GameMain.Server.CompressOutgoingMessage(msg);
|
||||
|
||||
netServer.SendMessage(msg, recipient.Connection, NetDeliveryMethod.Unreliable);
|
||||
|
||||
netServer.Send(msg, recipient.Connection, DeliveryMethod.Unreliable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -19,7 +18,7 @@ namespace Barotrauma
|
||||
set { allowModeVoting = value; }
|
||||
}
|
||||
|
||||
public void ServerRead(NetIncomingMessage inc, Client sender)
|
||||
public void ServerRead(IReadMessage inc, Client sender)
|
||||
{
|
||||
if (GameMain.Server == null || sender == null) return;
|
||||
|
||||
@@ -86,7 +85,7 @@ namespace Barotrauma
|
||||
GameMain.Server.UpdateVoteStatus();
|
||||
}
|
||||
|
||||
public void ServerWrite(NetBuffer msg)
|
||||
public void ServerWrite(IWriteMessage msg)
|
||||
{
|
||||
if (GameMain.Server == null) return;
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -127,7 +126,7 @@ namespace Barotrauma.Networking
|
||||
whitelistedPlayers.Add(new WhiteListedPlayer(name, ip));
|
||||
}
|
||||
|
||||
public void ServerAdminWrite(NetBuffer outMsg, Client c)
|
||||
public void ServerAdminWrite(IWriteMessage outMsg, Client c)
|
||||
{
|
||||
if (!c.HasPermission(ClientPermissions.ManageSettings))
|
||||
{
|
||||
@@ -139,7 +138,7 @@ namespace Barotrauma.Networking
|
||||
outMsg.Write(Enabled);
|
||||
|
||||
outMsg.WritePadBits();
|
||||
outMsg.WriteVariableInt32(whitelistedPlayers.Count);
|
||||
outMsg.WriteVariableUInt32((UInt32)whitelistedPlayers.Count);
|
||||
for (int i = 0; i < whitelistedPlayers.Count; i++)
|
||||
{
|
||||
WhiteListedPlayer whitelistedPlayer = whitelistedPlayers[i];
|
||||
@@ -154,13 +153,13 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public bool ServerAdminRead(NetBuffer incMsg, Client c)
|
||||
public bool ServerAdminRead(IReadMessage incMsg, Client c)
|
||||
{
|
||||
if (!c.HasPermission(ClientPermissions.ManageSettings))
|
||||
{
|
||||
bool enabled = incMsg.ReadBoolean(); incMsg.ReadPadBits();
|
||||
UInt16 removeCount = incMsg.ReadUInt16();
|
||||
incMsg.Position += removeCount * 4 * 8;
|
||||
incMsg.BitPosition += removeCount * 4 * 8;
|
||||
UInt16 addCount = incMsg.ReadUInt16();
|
||||
for (int i = 0; i < addCount; i++)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user