Unstable v0.19.5.0

This commit is contained in:
Juan Pablo Arce
2022-09-14 12:47:17 -03:00
parent 3f2c843247
commit 1fd2a51bbb
158 changed files with 5702 additions and 4813 deletions
@@ -2,6 +2,8 @@
using Barotrauma.Steam;
using System;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.Xna.Framework;
namespace Barotrauma.Networking
{
@@ -10,37 +12,14 @@ namespace Barotrauma.Networking
public ImmutableArray<ServerContentPackage> ServerContentPackages { get; set; } =
ImmutableArray<ServerContentPackage>.Empty;
public delegate void MessageCallback(IReadMessage message);
public delegate void DisconnectCallback(bool disableReconnect);
public delegate void DisconnectMessageCallback(string message);
public delegate void PasswordCallback(int salt, int retries);
public delegate void InitializationCompleteCallback();
[Obsolete("TODO: delete in nr3-layer-1-2-cleanup")]
public readonly struct Callbacks
public readonly record struct Callbacks(
Callbacks.MessageCallback OnMessageReceived,
Callbacks.DisconnectCallback OnDisconnect,
Callbacks.InitializationCompleteCallback OnInitializationComplete)
{
public readonly MessageCallback OnMessageReceived;
public readonly DisconnectCallback OnDisconnect;
public readonly DisconnectMessageCallback OnDisconnectMessageReceived;
public readonly PasswordCallback OnRequestPassword;
public readonly InitializationCompleteCallback OnInitializationComplete;
public Callbacks(MessageCallback onMessageReceived,
DisconnectCallback onDisconnect,
DisconnectMessageCallback onDisconnectMessageReceived,
PasswordCallback onRequestPassword,
InitializationCompleteCallback onInitializationComplete)
{
OnMessageReceived = onMessageReceived;
OnDisconnect = onDisconnect;
OnDisconnectMessageReceived = onDisconnectMessageReceived;
OnRequestPassword = onRequestPassword;
OnInitializationComplete = onInitializationComplete;
}
public delegate void MessageCallback(IReadMessage message);
public delegate void DisconnectCallback(PeerDisconnectPacket disconnectPacket);
public delegate void InitializationCompleteCallback();
}
protected readonly Callbacks callbacks;
@@ -51,6 +30,8 @@ namespace Barotrauma.Networking
protected readonly bool isOwner;
protected readonly Option<int> ownerKey;
protected bool isActive;
public ClientPeer(Endpoint serverEndpoint, Callbacks callbacks, Option<int> ownerKey)
{
ServerEndpoint = serverEndpoint;
@@ -60,7 +41,7 @@ namespace Barotrauma.Networking
}
public abstract void Start();
public abstract void Close(string? msg = null, bool disableReconnect = false);
public abstract void Close(PeerDisconnectPacket peerDisconnectPacket);
public abstract void Update(float deltaTime);
public abstract void Send(IWriteMessage msg, DeliveryMethod deliveryMethod, bool compressPastThreshold = true);
public abstract void SendPassword(string password);
@@ -71,6 +52,12 @@ namespace Barotrauma.Networking
public bool ContentPackageOrderReceived { get; protected set; }
protected int passwordSalt;
protected Steamworks.AuthTicket? steamAuthTicket;
private GUIMessageBox? passwordMsgBox;
public bool WaitingForPassword
=> isActive && initializationStep == ConnectionInitialization.Password
&& passwordMsgBox != null
&& GUIMessageBox.MessageBoxes.Contains(passwordMsgBox);
public struct IncomingInitializationMessage
{
@@ -112,8 +99,9 @@ namespace Barotrauma.Networking
}
case ConnectionInitialization.ContentPackageOrder:
{
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion ||
initializationStep == ConnectionInitialization.Password)
if (initializationStep
is ConnectionInitialization.SteamTicketAndVersion
or ConnectionInitialization.Password)
{
initializationStep = ConnectionInitialization.ContentPackageOrder;
}
@@ -155,10 +143,57 @@ namespace Barotrauma.Networking
var passwordPacket = INetSerializableStruct.Read<ServerPeerPasswordPacket>(inc.Message);
if (WaitingForPassword) { return; }
passwordPacket.Salt.TryUnwrap(out passwordSalt);
passwordPacket.RetriesLeft.TryUnwrap(out var retries);
callbacks.OnRequestPassword.Invoke(passwordSalt, retries);
LocalizedString pwMsg = TextManager.Get("PasswordRequired");
passwordMsgBox = new GUIMessageBox(pwMsg, "", new LocalizedString[] { TextManager.Get("OK"), TextManager.Get("Cancel") },
relativeSize: new Vector2(0.25f, 0.1f), minSize: new Point(400, GUI.IntScale(170)));
var passwordHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), passwordMsgBox.Content.RectTransform), childAnchor: Anchor.TopCenter);
var passwordBox = new GUITextBox(new RectTransform(new Vector2(0.8f, 1f), passwordHolder.RectTransform) { MinSize = new Point(0, 20) })
{
Censor = true
};
if (retries > 0)
{
var incorrectPasswordText = new GUITextBlock(new RectTransform(new Vector2(1f, 0.0f), passwordHolder.RectTransform), TextManager.Get("incorrectpassword"), GUIStyle.Red, GUIStyle.Font, textAlignment: Alignment.Center);
incorrectPasswordText.RectTransform.MinSize = new Point(0, (int)incorrectPasswordText.TextSize.Y);
passwordHolder.Recalculate();
}
passwordMsgBox.Content.Recalculate();
passwordMsgBox.Content.RectTransform.MinSize = new Point(0, passwordMsgBox.Content.RectTransform.Children.Sum(c => c.Rect.Height));
passwordMsgBox.Content.Parent.RectTransform.MinSize = new Point(0, (int)(passwordMsgBox.Content.RectTransform.MinSize.Y / passwordMsgBox.Content.RectTransform.RelativeSize.Y));
var okButton = passwordMsgBox.Buttons[0];
okButton.OnClicked += (_, __) =>
{
SendPassword(passwordBox.Text);
return true;
};
okButton.OnClicked += passwordMsgBox.Close;
var cancelButton = passwordMsgBox.Buttons[1];
cancelButton.OnClicked = (_, __) =>
{
Close(PeerDisconnectPacket.WithReason(DisconnectReason.Disconnected));
passwordMsgBox?.Close(); passwordMsgBox = null;
return true;
};
passwordBox.OnEnterPressed += (_, __) =>
{
okButton.OnClicked.Invoke(okButton, okButton.UserData);
return true;
};
passwordBox.Select();
break;
}
}
@@ -9,7 +9,6 @@ namespace Barotrauma.Networking
{
internal sealed class LidgrenClientPeer : ClientPeer
{
private bool isActive;
private NetClient? netClient;
private readonly NetPeerConfiguration netPeerConfiguration;
@@ -94,7 +93,7 @@ namespace Barotrauma.Networking
if (isOwner && !(ChildServerRelay.Process is { HasExited: false }))
{
Close();
Close(PeerDisconnectPacket.WithReason(DisconnectReason.ServerCrashed));
var msgBox = new GUIMessageBox(TextManager.Get("ConnectionLost"), ChildServerRelay.CrashMessage);
msgBox.Buttons[0].OnClicked += (btn, obj) =>
{
@@ -140,8 +139,10 @@ namespace Barotrauma.Networking
var (_, packetHeader, initialization) = INetSerializableStruct.Read<PeerPacketHeaders>(inc);
if (packetHeader.IsConnectionInitializationStep() && initializationStep != ConnectionInitialization.Success)
if (packetHeader.IsConnectionInitializationStep())
{
if (initializationStep == ConnectionInitialization.Success) { return; }
ReadConnectionInitializationStep(new IncomingInitializationMessage
{
InitializationStep = initialization ?? throw new Exception("Initialization step missing"),
@@ -170,8 +171,9 @@ namespace Barotrauma.Networking
{
case NetConnectionStatus.Disconnected:
string disconnectMsg = inc.ReadString();
Close(disconnectMsg);
callbacks.OnDisconnectMessageReceived.Invoke(disconnectMsg);
var peerDisconnectPacket =
PeerDisconnectPacket.FromLidgrenStringRepresentation(disconnectMsg);
Close(peerDisconnectPacket.Fallback(PeerDisconnectPacket.WithReason(DisconnectReason.Unknown)));
break;
}
}
@@ -198,7 +200,7 @@ namespace Barotrauma.Networking
SendMsgInternal(headers, body);
}
public override void Close(string? msg = null, bool disableReconnect = false)
public override void Close(PeerDisconnectPacket peerDisconnectPacket)
{
if (!isActive) { return; }
@@ -206,13 +208,13 @@ namespace Barotrauma.Networking
isActive = false;
netClient.Shutdown(msg ?? TextManager.Get("Disconnecting").Value);
netClient.Shutdown(peerDisconnectPacket.ToLidgrenStringRepresentation());
netClient = null;
steamAuthTicket?.Cancel();
steamAuthTicket = null;
callbacks.OnDisconnect.Invoke(disableReconnect);
callbacks.OnDisconnect.Invoke(peerDisconnectPacket);
}
public override void Send(IWriteMessage msg, DeliveryMethod deliveryMethod, bool compressPastThreshold = true)
@@ -10,7 +10,6 @@ namespace Barotrauma.Networking
{
internal sealed class SteamP2PClientPeer : ClientPeer
{
private bool isActive;
private readonly SteamId hostSteamId;
private double timeout;
private double heartbeatTimer;
@@ -97,8 +96,7 @@ namespace Barotrauma.Networking
if (steamId != hostSteamId.Value) { return; }
Close($"SteamP2P connection failed: {error}");
callbacks.OnDisconnectMessageReceived.Invoke($"{DisconnectReason.SteamP2PError}/SteamP2P connection failed: {error}");
Close(PeerDisconnectPacket.SteamP2PError(error));
}
private void OnP2PData(ulong steamId, byte[] data, int dataLength)
@@ -117,8 +115,10 @@ namespace Barotrauma.Networking
if (!packetHeader.IsServerMessage()) { return; }
if (packetHeader.IsConnectionInitializationStep() && initialization.HasValue)
if (packetHeader.IsConnectionInitializationStep())
{
if (!initialization.HasValue) { return; }
var relayPacket = INetSerializableStruct.Read<SteamP2PInitializationRelayPacket>(inc);
SteamManager.JoinLobby(relayPacket.LobbyID, false);
@@ -127,7 +127,7 @@ namespace Barotrauma.Networking
incomingInitializationMessages.Add(new IncomingInitializationMessage
{
InitializationStep = initialization.Value,
Message = relayPacket.Message.GetReadMessage()
Message = relayPacket.Message.GetReadMessageUncompressed()
});
}
}
@@ -138,13 +138,12 @@ namespace Barotrauma.Networking
else if (packetHeader.IsDisconnectMessage())
{
PeerDisconnectPacket packet = INetSerializableStruct.Read<PeerDisconnectPacket>(inc);
Close(packet.Message);
callbacks.OnDisconnectMessageReceived.Invoke(packet.Message);
Close(packet);
}
else
{
var packet = INetSerializableStruct.Read<PeerPacketMessage>(inc);
incomingDataMessages.Add(packet.GetReadMessage());
incomingDataMessages.Add(packet.GetReadMessage(packetHeader.IsCompressed(), ServerConnection!));
}
}
@@ -170,14 +169,12 @@ namespace Barotrauma.Networking
{
if (state.P2PSessionError != Steamworks.P2PSessionError.None)
{
Close($"SteamP2P error code: {state.P2PSessionError}");
callbacks.OnDisconnectMessageReceived.Invoke($"{DisconnectReason.SteamP2PError}/SteamP2P error code: {state.P2PSessionError}");
Close(PeerDisconnectPacket.SteamP2PError(state.P2PSessionError));
}
}
else
{
Close("SteamP2P connection could not be established");
callbacks.OnDisconnectMessageReceived.Invoke(DisconnectReason.SteamP2PError.ToString());
Close(PeerDisconnectPacket.WithReason(DisconnectReason.Timeout));
}
connectionStatusTimer = 1.0f;
@@ -212,8 +209,7 @@ namespace Barotrauma.Networking
if (timeout < 0.0)
{
Close("Timed out");
callbacks.OnDisconnectMessageReceived.Invoke(DisconnectReason.SteamP2PTimeOut.ToString());
Close(PeerDisconnectPacket.WithReason(DisconnectReason.SteamP2PTimeOut));
return;
}
@@ -221,20 +217,26 @@ namespace Barotrauma.Networking
{
if (incomingDataMessages.Count > 0)
{
var incomingMessage = incomingDataMessages.First();
byte incomingHeader = incomingMessage.LengthBytes > 0 ? incomingMessage.PeekByte() : (byte)0;
if (ContentPackageOrderReceived)
void initializationError(string errorMsg, string analyticsTag)
{
#warning: TODO: do not allow completing initialization until content package order has been received?
string errorMsg = $"Error during connection initialization: completed initialization before receiving content package order. Incoming header: {incomingHeader}";
GameAnalyticsManager.AddErrorEventOnce("SteamP2PClientPeer.OnInitializationComplete:ContentPackageOrderNotReceived", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce($"SteamP2PClientPeer.OnInitializationComplete:{analyticsTag}", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
DebugConsole.ThrowError(errorMsg);
Close(PeerDisconnectPacket.WithReason(DisconnectReason.Disconnected));
}
if (!ContentPackageOrderReceived)
{
initializationError(
errorMsg: "Error during connection initialization: completed initialization before receiving content package order.",
analyticsTag: "ContentPackageOrderNotReceived");
return;
}
if (ServerContentPackages.Length == 0)
{
string errorMsg = $"Error during connection initialization: list of content packages enabled on the server was empty when completing initialization. Incoming header: {incomingHeader}";
GameAnalyticsManager.AddErrorEventOnce("SteamP2PClientPeer.OnInitializationComplete:NoContentPackages", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
DebugConsole.ThrowError(errorMsg);
initializationError(
errorMsg: "Error during connection initialization: list of content packages enabled on the server was empty when completing initialization.",
analyticsTag: "NoContentPackages");
return;
}
callbacks.OnInitializationComplete.Invoke();
initializationStep = ConnectionInitialization.Success;
@@ -320,7 +322,7 @@ namespace Barotrauma.Networking
SendMsgInternal(headers, body);
}
public override void Close(string? msg = null, bool disableReconnect = false)
public override void Close(PeerDisconnectPacket peerDisconnectPacket)
{
if (!isActive) { return; }
@@ -334,12 +336,7 @@ namespace Barotrauma.Networking
PacketHeader = PacketHeader.IsDisconnectMessage,
Initialization = null
};
var body = new PeerDisconnectPacket
{
Message = msg ?? "Disconnected"
};
SendMsgInternal(headers, body);
SendMsgInternal(headers, peerDisconnectPacket);
Thread.Sleep(100);
@@ -349,7 +346,7 @@ namespace Barotrauma.Networking
steamAuthTicket?.Cancel();
steamAuthTicket = null;
callbacks.OnDisconnect.Invoke(disableReconnect);
callbacks.OnDisconnect.Invoke(peerDisconnectPacket);
}
protected override void SendMsgInternal(PeerPacketHeaders headers, INetSerializableStruct? body)
@@ -9,8 +9,6 @@ namespace Barotrauma.Networking
{
sealed class SteamP2POwnerPeer : ClientPeer
{
private bool isActive;
private readonly SteamId selfSteamID;
private UInt64 ownerKey64 => unchecked((UInt64)ownerKey.Fallback(0));
@@ -68,6 +66,7 @@ namespace Barotrauma.Networking
: throw new InvalidOperationException("Steamworks not initialized");
}
public override void Start()
{
if (isActive) { return; }
@@ -93,22 +92,13 @@ namespace Barotrauma.Networking
private void OnAuthChange(Steamworks.SteamId steamId, Steamworks.SteamId ownerId, Steamworks.AuthResponse status)
{
RemotePeer? remotePeer = remotePeers.Find(p => p.SteamId.Value == steamId);
DebugConsole.Log($"{steamId} validation: {status}, {remotePeer != null}");
if (remotePeer == null) { return; }
if (remotePeer.Authenticated)
{
if (status != Steamworks.AuthResponse.OK)
{
DisconnectPeer(remotePeer, $"{DisconnectReason.SteamAuthenticationFailed}/ Steam authentication status changed: {status}");
}
return;
}
if (status == Steamworks.AuthResponse.OK)
{
if (remotePeer.Authenticated) { return; }
SteamId ownerSteamId = new SteamId(ownerId);
remotePeer.OwnerSteamId = Option<SteamId>.Some(ownerSteamId);
remotePeer.Authenticated = true;
@@ -126,7 +116,7 @@ namespace Barotrauma.Networking
}
else
{
DisconnectPeer(remotePeer, $"{DisconnectReason.SteamAuthenticationFailed}/ Steam authentication failed: {status}");
DisconnectPeer(remotePeer, PeerDisconnectPacket.SteamAuthError(status));
}
}
@@ -171,7 +161,7 @@ namespace Barotrauma.Networking
Steamworks.BeginAuthResult authSessionStartState = SteamManager.StartAuthSession(ticket, steamId);
if (authSessionStartState != Steamworks.BeginAuthResult.OK)
{
DisconnectPeer(remotePeer, $"{DisconnectReason.SteamAuthenticationFailed}/ Steam auth session failed to start: {authSessionStartState}");
DisconnectPeer(remotePeer, PeerDisconnectPacket.SteamAuthError(authSessionStartState));
return;
}
}
@@ -197,9 +187,9 @@ namespace Barotrauma.Networking
{
if (!isActive) { return; }
if (ChildServerRelay.HasShutDown || (ChildServerRelay.Process?.HasExited ?? true))
if (ChildServerRelay.HasShutDown || !(ChildServerRelay.Process is { HasExited: false }))
{
Close();
Close(PeerDisconnectPacket.WithReason(DisconnectReason.ServerCrashed));
var msgBox = new GUIMessageBox(TextManager.Get("ConnectionLost"), ChildServerRelay.CrashMessage);
msgBox.Buttons[0].OnClicked += (btn, obj) =>
{
@@ -279,7 +269,7 @@ namespace Barotrauma.Networking
if (packetHeader.IsDisconnectMessage())
{
var packet = INetSerializableStruct.Read<PeerDisconnectPacket>(inc);
DisconnectPeer(peer, packet.Message);
DisconnectPeer(peer, packet);
return;
}
@@ -366,30 +356,20 @@ namespace Barotrauma.Networking
}
}
private void DisconnectPeer(RemotePeer peer, string msg)
private void DisconnectPeer(RemotePeer peer, PeerDisconnectPacket peerDisconnectPacket)
{
if (!string.IsNullOrWhiteSpace(msg))
{
peer.DisconnectTime ??= Timing.TotalTime + 1.0;
peer.DisconnectTime ??= Timing.TotalTime + 1.0;
IWriteMessage outMsg = new WriteOnlyMessage();
outMsg.WriteNetSerializableStruct(new PeerPacketHeaders
{
DeliveryMethod = DeliveryMethod.Reliable,
PacketHeader = PacketHeader.IsServerMessage | PacketHeader.IsDisconnectMessage
});
outMsg.WriteNetSerializableStruct(new PeerDisconnectPacket
{
Message = msg
});
Steamworks.SteamNetworking.SendP2PPacket(peer.SteamId.Value, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
}
else
IWriteMessage outMsg = new WriteOnlyMessage();
outMsg.WriteNetSerializableStruct(new PeerPacketHeaders
{
ClosePeerSession(peer);
}
DeliveryMethod = DeliveryMethod.Reliable,
PacketHeader = PacketHeader.IsServerMessage | PacketHeader.IsDisconnectMessage
});
outMsg.WriteNetSerializableStruct(peerDisconnectPacket);
Steamworks.SteamNetworking.SendP2PPacket(peer.SteamId.Value, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
}
private void ClosePeerSession(RemotePeer peer)
@@ -403,7 +383,7 @@ namespace Barotrauma.Networking
//owner doesn't send passwords
}
public override void Close(string? msg = null, bool disableReconnect = false)
public override void Close(PeerDisconnectPacket peerDisconnectPacket)
{
if (!isActive) { return; }
@@ -411,7 +391,7 @@ namespace Barotrauma.Networking
for (int i = remotePeers.Count - 1; i >= 0; i--)
{
DisconnectPeer(remotePeers[i], msg ?? DisconnectReason.ServerShutdown.ToString());
DisconnectPeer(remotePeers[i], peerDisconnectPacket);
}
Thread.Sleep(100);
@@ -423,7 +403,7 @@ namespace Barotrauma.Networking
ChildServerRelay.ClosePipes();
callbacks.OnDisconnect.Invoke(disableReconnect);
callbacks.OnDisconnect.Invoke(peerDisconnectPacket);
SteamManager.LeaveLobby();
Steamworks.SteamNetworking.ResetActions();