v0.10.5.1

This commit is contained in:
Juan Pablo Arce
2020-09-22 11:31:56 -03:00
parent 44032d0ae0
commit 0002ad2c50
343 changed files with 12276 additions and 5023 deletions
@@ -1,13 +1,56 @@
using System;
using Barotrauma.Extensions;
using Barotrauma.Steam;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Barotrauma.Networking
{
abstract class ClientPeer
{
protected class ServerContentPackage
{
public string Name;
public string Hash;
public UInt64 WorkshopId;
public ContentPackage RegularPackage
{
get
{
return ContentPackage.RegularPackages.Find(p => p.MD5hash.Hash.Equals(Hash));
}
}
public ContentPackage CorePackage
{
get
{
return ContentPackage.CorePackages.Find(p => p.MD5hash.Hash.Equals(Hash));
}
}
public ServerContentPackage(string name, string hash, UInt64 workshopId)
{
Name = name;
Hash = hash;
WorkshopId = workshopId;
}
}
protected string GetPackageStr(ContentPackage contentPackage)
{
return "\"" + contentPackage.Name + "\" (hash " + contentPackage.MD5hash.ShortHash + ")";
}
protected string GetPackageStr(ServerContentPackage contentPackage)
{
return "\"" + contentPackage.Name + "\" (hash " + Md5Hash.GetShortHash(contentPackage.Hash) + ")";
}
public delegate void MessageCallback(IReadMessage message);
public delegate void DisconnectCallback();
public delegate void DisconnectCallback(bool disableReconnect);
public delegate void DisconnectMessageCallback(string message);
public delegate void PasswordCallback(int salt, int retries);
public delegate void InitializationCompleteCallback();
@@ -25,11 +68,150 @@ namespace Barotrauma.Networking
public NetworkConnection ServerConnection { get; protected set; }
public abstract void Start(object endPoint, int ownerKey);
public abstract void Close(string msg = null);
public abstract void Close(string msg = null, bool disableReconnect = false);
public abstract void Update(float deltaTime);
public abstract void Send(IWriteMessage msg, DeliveryMethod deliveryMethod);
public abstract void SendPassword(string password);
protected abstract void SendMsgInternal(DeliveryMethod deliveryMethod, IWriteMessage msg);
protected ConnectionInitialization initializationStep;
protected bool contentPackageOrderReceived;
protected int ownerKey = 0;
protected int passwordSalt;
protected Steamworks.AuthTicket steamAuthTicket;
protected void ReadConnectionInitializationStep(IReadMessage inc)
{
ConnectionInitialization step = (ConnectionInitialization)inc.ReadByte();
IWriteMessage outMsg;
switch (step)
{
case ConnectionInitialization.SteamTicketAndVersion:
if (initializationStep != ConnectionInitialization.SteamTicketAndVersion) { return; }
outMsg = new WriteOnlyMessage();
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
outMsg.Write((byte)ConnectionInitialization.SteamTicketAndVersion);
outMsg.Write(Name);
outMsg.Write(ownerKey);
outMsg.Write(SteamManager.GetSteamID());
if (steamAuthTicket == null)
{
outMsg.Write((UInt16)0);
}
else
{
outMsg.Write((UInt16)steamAuthTicket.Data.Length);
outMsg.Write(steamAuthTicket.Data, 0, steamAuthTicket.Data.Length);
}
outMsg.Write(GameMain.Version.ToString());
outMsg.Write(GameMain.Config.Language);
SendMsgInternal(DeliveryMethod.Reliable, outMsg);
break;
case ConnectionInitialization.ContentPackageOrder:
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion ||
initializationStep == ConnectionInitialization.Password) { initializationStep = ConnectionInitialization.ContentPackageOrder; }
if (initializationStep != ConnectionInitialization.ContentPackageOrder) { return; }
outMsg = new WriteOnlyMessage();
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
outMsg.Write((byte)ConnectionInitialization.ContentPackageOrder);
string serverName = inc.ReadString();
UInt32 cpCount = inc.ReadVariableUInt32();
ServerContentPackage corePackage = null;
List<ServerContentPackage> regularPackages = new List<ServerContentPackage>();
List<ServerContentPackage> missingPackages = new List<ServerContentPackage>();
for (int i = 0; i < cpCount; i++)
{
string name = inc.ReadString();
string hash = inc.ReadString();
UInt64 workshopId = inc.ReadUInt64();
var pkg = new ServerContentPackage(name, hash, workshopId);
if (pkg.CorePackage != null)
{
corePackage = pkg;
}
else if (pkg.RegularPackage != null)
{
regularPackages.Add(pkg);
}
else
{
missingPackages.Add(pkg);
}
}
if (missingPackages.Count > 0)
{
var nonDownloadable = missingPackages.Where(p => p.WorkshopId == 0);
if (nonDownloadable.Any())
{
string disconnectMsg;
if (nonDownloadable.Count() == 1)
{
disconnectMsg = $"DisconnectMessage.MissingContentPackage~[missingcontentpackage]={GetPackageStr(missingPackages[0])}";
}
else
{
List<string> packageStrs = new List<string>();
nonDownloadable.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
disconnectMsg = $"DisconnectMessage.MissingContentPackages~[missingcontentpackages]={string.Join(", ", packageStrs)}";
}
Close(disconnectMsg, disableReconnect: true);
}
else
{
Close(disableReconnect: true);
string missingModNames = "\n- " + string.Join("\n\n- ", missingPackages.Select(p => GetPackageStr(p))) + "\n\n";
var msgBox = new GUIMessageBox(
TextManager.Get("WorkshopItemDownloadTitle"),
TextManager.GetWithVariable("WorkshopItemDownloadPrompt", "[items]", missingModNames),
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
msgBox.Buttons[0].OnClicked = (yesBtn, userdata) =>
{
GameMain.ServerListScreen.Select();
GameMain.ServerListScreen.DownloadWorkshopItems(missingPackages.Select(p => p.WorkshopId), serverName, ServerConnection.EndPointString);
return true;
};
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked = msgBox.Close;
}
return;
}
if (!contentPackageOrderReceived)
{
GameMain.Config.SwapPackages(corePackage.CorePackage, regularPackages.Select(p => p.RegularPackage).ToList());
contentPackageOrderReceived = true;
}
SendMsgInternal(DeliveryMethod.Reliable, outMsg);
break;
case ConnectionInitialization.Password:
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion) { initializationStep = ConnectionInitialization.Password; }
if (initializationStep != ConnectionInitialization.Password) { return; }
bool incomingSalt = inc.ReadBoolean(); inc.ReadPadBits();
int retries = 0;
if (incomingSalt)
{
passwordSalt = inc.ReadInt32();
}
else
{
retries = inc.ReadInt32();
}
OnRequestPassword?.Invoke(passwordSalt, retries);
break;
}
}
#if DEBUG
public abstract void ForceTimeOut();
#endif
@@ -14,11 +14,6 @@ namespace Barotrauma.Networking
private NetClient netClient;
private NetPeerConfiguration netPeerConfiguration;
private ConnectionInitialization initializationStep;
private bool contentPackageOrderReceived;
private int ownerKey;
private int passwordSalt;
private Steamworks.AuthTicket steamAuthTicket;
List<NetIncomingMessage> incomingLidgrenMessages;
public LidgrenClientPeer(string name)
@@ -128,7 +123,7 @@ namespace Barotrauma.Networking
if (isConnectionInitializationStep && initializationStep != ConnectionInitialization.Success)
{
ReadConnectionInitializationStep(inc);
ReadConnectionInitializationStep(new ReadWriteMessage(inc.Data, (int)inc.Position, inc.LengthBits, false));
}
else
{
@@ -158,99 +153,6 @@ namespace Barotrauma.Networking
}
}
private void ReadConnectionInitializationStep(NetIncomingMessage inc)
{
if (!isActive) { return; }
ConnectionInitialization step = (ConnectionInitialization)inc.ReadByte();
//Console.WriteLine(step + " " + initializationStep);
NetOutgoingMessage outMsg; NetSendResult result;
switch (step)
{
case ConnectionInitialization.SteamTicketAndVersion:
if (initializationStep != ConnectionInitialization.SteamTicketAndVersion) { return; }
outMsg = netClient.CreateMessage();
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
outMsg.Write((byte)ConnectionInitialization.SteamTicketAndVersion);
outMsg.Write(Name);
outMsg.Write(ownerKey);
outMsg.Write(SteamManager.GetSteamID());
if (steamAuthTicket == null)
{
outMsg.Write((UInt16)0);
}
else
{
outMsg.Write((UInt16)steamAuthTicket.Data.Length);
outMsg.Write(steamAuthTicket.Data, 0, steamAuthTicket.Data.Length);
}
outMsg.Write(GameMain.Version.ToString());
IEnumerable<ContentPackage> mpContentPackages = GameMain.SelectedPackages.Where(cp => cp.HasMultiplayerIncompatibleContent);
outMsg.WriteVariableInt32(mpContentPackages.Count());
foreach (ContentPackage contentPackage in mpContentPackages)
{
outMsg.Write(contentPackage.Name);
outMsg.Write(contentPackage.MD5hash.Hash);
}
result = netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
{
DebugConsole.NewMessage("Failed to send "+initializationStep.ToString()+" message to host: " + result);
}
break;
case ConnectionInitialization.ContentPackageOrder:
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion ||
initializationStep == ConnectionInitialization.Password) { initializationStep = ConnectionInitialization.ContentPackageOrder; }
if (initializationStep != ConnectionInitialization.ContentPackageOrder) { return; }
outMsg = netClient.CreateMessage();
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
outMsg.Write((byte)ConnectionInitialization.ContentPackageOrder);
Int32 cpCount = inc.ReadVariableInt32();
List<ContentPackage> serverContentPackages = new List<ContentPackage>();
for (int i = 0; i < cpCount; i++)
{
string hash = inc.ReadString();
serverContentPackages.Add(GameMain.Config.SelectedContentPackages.Find(cp => cp.MD5hash.Hash == hash));
}
if (!contentPackageOrderReceived)
{
GameMain.Config.ReorderSelectedContentPackages(cp => serverContentPackages.Contains(cp) ?
serverContentPackages.IndexOf(cp) :
serverContentPackages.Count + GameMain.Config.SelectedContentPackages.IndexOf(cp));
contentPackageOrderReceived = true;
}
result = netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
{
DebugConsole.NewMessage("Failed to send " + initializationStep.ToString() + " message to host: " + result);
}
break;
case ConnectionInitialization.Password:
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion) { initializationStep = ConnectionInitialization.Password; }
if (initializationStep != ConnectionInitialization.Password) { return; }
bool incomingSalt = inc.ReadBoolean(); inc.ReadPadBits();
int retries = 0;
if (incomingSalt)
{
passwordSalt = inc.ReadInt32();
}
else
{
retries = inc.ReadInt32();
}
OnRequestPassword?.Invoke(passwordSalt, retries);
break;
}
}
public override void SendPassword(string password)
{
if (!isActive) { return; }
@@ -269,7 +171,7 @@ namespace Barotrauma.Networking
}
}
public override void Close(string msg = null)
public override void Close(string msg = null, bool disableReconnect = false)
{
if (!isActive) { return; }
@@ -278,7 +180,7 @@ namespace Barotrauma.Networking
netClient.Shutdown(msg ?? TextManager.Get("Disconnecting"));
netClient = null;
steamAuthTicket?.Cancel(); steamAuthTicket = null;
OnDisconnect?.Invoke();
OnDisconnect?.Invoke(disableReconnect);
}
public override void Send(IWriteMessage msg, DeliveryMethod deliveryMethod)
@@ -320,6 +222,18 @@ namespace Barotrauma.Networking
}
}
protected override void SendMsgInternal(DeliveryMethod deliveryMethod, IWriteMessage msg)
{
NetOutgoingMessage lidgrenMsg = netClient.CreateMessage();
lidgrenMsg.Write(msg.Buffer, 0, msg.LengthBytes);
NetSendResult result = netClient.SendMessage(lidgrenMsg, NetDeliveryMethod.ReliableUnordered);
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
{
DebugConsole.NewMessage("Failed to send message to host: " + result + "\n" + Environment.StackTrace);
}
}
#if DEBUG
public override void ForceTimeOut()
{
@@ -12,10 +12,6 @@ namespace Barotrauma.Networking
{
private bool isActive;
private UInt64 hostSteamId;
private ConnectionInitialization initializationStep;
private bool contentPackageOrderReceived;
private int passwordSalt;
private Steamworks.AuthTicket steamAuthTicket;
private double timeout;
private double heartbeatTimer;
private double connectionStatusTimer;
@@ -89,6 +85,7 @@ namespace Barotrauma.Networking
Steamworks.SteamNetworking.AcceptP2PSessionWithUser(steamId);
}
else if (initializationStep != ConnectionInitialization.Password &&
initializationStep != ConnectionInitialization.ContentPackageOrder &&
initializationStep != ConnectionInitialization.Success)
{
DebugConsole.ThrowError($"Connection from incorrect SteamID was rejected: "+
@@ -105,7 +102,7 @@ namespace Barotrauma.Networking
OnDisconnectMessageReceived?.Invoke($"SteamP2P connection failed: {error}");
}
private void OnP2PData(ulong steamId, byte[] data, int dataLength, int channel)
private void OnP2PData(ulong steamId, byte[] data, int dataLength)
{
if (!isActive) { return; }
if (steamId != hostSteamId) { return; }
@@ -165,6 +162,7 @@ namespace Barotrauma.Networking
heartbeatTimer -= deltaTime;
if (initializationStep != ConnectionInitialization.Password &&
initializationStep != ConnectionInitialization.ContentPackageOrder &&
initializationStep != ConnectionInitialization.Success)
{
connectionStatusTimer -= deltaTime;
@@ -194,7 +192,7 @@ namespace Barotrauma.Networking
var packet = Steamworks.SteamNetworking.ReadP2PPacket();
if (packet.HasValue)
{
OnP2PData(packet?.SteamId ?? 0, packet?.Data, packet?.Data.Length ?? 0, 0);
OnP2PData(packet?.SteamId ?? 0, packet?.Data, packet?.Data.Length ?? 0);
receivedBytes += packet?.Data.Length ?? 0;
}
}
@@ -249,88 +247,6 @@ namespace Barotrauma.Networking
incomingDataMessages.Clear();
}
private void ReadConnectionInitializationStep(IReadMessage inc)
{
if (!isActive) { return; }
ConnectionInitialization step = (ConnectionInitialization)inc.ReadByte();
IWriteMessage outMsg;
//DebugConsole.NewMessage(step + " " + initializationStep);
switch (step)
{
case ConnectionInitialization.SteamTicketAndVersion:
if (initializationStep != ConnectionInitialization.SteamTicketAndVersion) { return; }
outMsg = new WriteOnlyMessage();
outMsg.Write((byte)DeliveryMethod.Reliable);
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
outMsg.Write((byte)ConnectionInitialization.SteamTicketAndVersion);
outMsg.Write(Name);
outMsg.Write(SteamManager.GetSteamID());
outMsg.Write((UInt16)steamAuthTicket.Data.Length);
outMsg.Write(steamAuthTicket.Data, 0, steamAuthTicket.Data.Length);
outMsg.Write(GameMain.Version.ToString());
IEnumerable<ContentPackage> mpContentPackages = GameMain.SelectedPackages.Where(cp => cp.HasMultiplayerIncompatibleContent);
outMsg.WriteVariableUInt32((UInt32)mpContentPackages.Count());
foreach (ContentPackage contentPackage in mpContentPackages)
{
outMsg.Write(contentPackage.Name);
outMsg.Write(contentPackage.MD5hash.Hash);
}
heartbeatTimer = 5.0;
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
break;
case ConnectionInitialization.ContentPackageOrder:
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion ||
initializationStep == ConnectionInitialization.Password) { initializationStep = ConnectionInitialization.ContentPackageOrder; }
if (initializationStep != ConnectionInitialization.ContentPackageOrder) { return; }
outMsg = new WriteOnlyMessage();
outMsg.Write((byte)DeliveryMethod.Reliable);
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
outMsg.Write((byte)ConnectionInitialization.ContentPackageOrder);
UInt32 cpCount = inc.ReadVariableUInt32();
List<ContentPackage> serverContentPackages = new List<ContentPackage>();
for (int i = 0; i < cpCount; i++)
{
string hash = inc.ReadString();
serverContentPackages.Add(GameMain.Config.SelectedContentPackages.Find(cp => cp.MD5hash.Hash == hash));
}
if (!contentPackageOrderReceived)
{
GameMain.Config.ReorderSelectedContentPackages(cp => serverContentPackages.Contains(cp) ?
serverContentPackages.IndexOf(cp) :
serverContentPackages.Count + GameMain.Config.SelectedContentPackages.IndexOf(cp));
contentPackageOrderReceived = true;
}
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
break;
case ConnectionInitialization.Password:
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion) { initializationStep = ConnectionInitialization.Password; }
if (initializationStep != ConnectionInitialization.Password) { return; }
bool incomingSalt = inc.ReadBoolean(); inc.ReadPadBits();
int retries = 0;
if (incomingSalt)
{
passwordSalt = inc.ReadInt32();
}
else
{
retries = inc.ReadInt32();
}
OnRequestPassword?.Invoke(passwordSalt, retries);
break;
}
}
public override void Send(IWriteMessage msg, DeliveryMethod deliveryMethod)
{
if (!isActive) { return; }
@@ -339,8 +255,7 @@ namespace Barotrauma.Networking
buf[0] = (byte)deliveryMethod;
byte[] bufAux = new byte[msg.LengthBytes];
bool isCompressed; int length;
msg.PrepareForSending(ref bufAux, out isCompressed, out length);
msg.PrepareForSending(ref bufAux, out bool isCompressed, out int length);
buf[1] = (byte)(isCompressed ? PacketHeader.IsCompressed : PacketHeader.None);
@@ -426,7 +341,7 @@ namespace Barotrauma.Networking
sentBytes += outMsg.LengthBytes;
}
public override void Close(string msg = null)
public override void Close(string msg = null, bool disableReconnect = false)
{
if (!isActive) { return; }
@@ -451,7 +366,7 @@ namespace Barotrauma.Networking
steamAuthTicket?.Cancel(); steamAuthTicket = null;
hostSteamId = 0;
OnDisconnect?.Invoke();
OnDisconnect?.Invoke(disableReconnect);
}
~SteamP2PClientPeer()
@@ -460,6 +375,31 @@ namespace Barotrauma.Networking
Close();
}
protected override void SendMsgInternal(DeliveryMethod deliveryMethod, IWriteMessage msg)
{
Steamworks.P2PSend sendType;
switch (deliveryMethod)
{
case DeliveryMethod.Reliable:
case DeliveryMethod.ReliableOrdered:
//the documentation seems to suggest that the Reliable send type
//enforces packet order (TODO: verify)
sendType = Steamworks.P2PSend.Reliable;
break;
default:
sendType = Steamworks.P2PSend.Unreliable;
break;
}
IWriteMessage msgToSend = new WriteOnlyMessage();
msgToSend.Write((byte)deliveryMethod);
msgToSend.Write(msg.Buffer, 0, msg.LengthBytes);
heartbeatTimer = 5.0;
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, msgToSend.Buffer, msgToSend.LengthBytes, 0, sendType);
sentBytes += msg.LengthBytes;
}
#if DEBUG
public override void ForceTimeOut()
{
@@ -1,8 +1,6 @@
using System;
using Barotrauma.Steam;
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using Barotrauma.Steam;
using System.Linq;
using System.Threading;
@@ -12,7 +10,6 @@ namespace Barotrauma.Networking
{
private bool isActive;
private ConnectionInitialization initializationStep;
private readonly UInt64 selfSteamID;
private long sentBytes, receivedBytes;
@@ -61,7 +58,7 @@ namespace Barotrauma.Networking
initializationStep = ConnectionInitialization.SteamTicketAndVersion;
ServerConnection = new PipeConnection();
ServerConnection = new PipeConnection(selfSteamID);
ServerConnection.Status = NetworkConnectionStatus.Connected;
remotePeers = new List<RemotePeer>();
@@ -161,6 +158,7 @@ namespace Barotrauma.Networking
remotePeer.Authenticating = true;
authMsg.ReadString(); //skip name
authMsg.ReadInt32(); //skip owner key
authMsg.ReadUInt64(); //skip steamid
UInt16 ticketLength = authMsg.ReadUInt16();
byte[] ticket = authMsg.ReadBytes(ticketLength);
@@ -395,7 +393,7 @@ namespace Barotrauma.Networking
return; //owner doesn't send passwords
}
public override void Close(string msg = null)
public override void Close(string msg = null, bool disableReconnect = false)
{
if (!isActive) { return; }
@@ -415,7 +413,7 @@ namespace Barotrauma.Networking
ChildServerRelay.ClosePipes();
OnDisconnect?.Invoke();
OnDisconnect?.Invoke(disableReconnect);
SteamManager.LeaveLobby();
Steamworks.SteamNetworking.ResetActions();
@@ -445,6 +443,12 @@ namespace Barotrauma.Networking
Close();
}
protected override void SendMsgInternal(DeliveryMethod deliveryMethod, IWriteMessage msg)
{
//not currently used by SteamP2POwnerPeer
throw new NotImplementedException();
}
#if DEBUG
public override void ForceTimeOut()
{