Unstable v0.19.1.0

This commit is contained in:
Juan Pablo Arce
2022-08-19 13:59:08 -03:00
parent 6b55adcdd9
commit 1219615d64
192 changed files with 3875 additions and 2648 deletions
@@ -1,28 +1,28 @@
using Barotrauma.Steam;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Barotrauma.Networking
{
partial class BannedPlayer
{
public BannedPlayer(string name, UInt16 uniqueIdentifier, bool isRangeBan, string endPoint, ulong steamID, string reason, DateTime? expiration)
public BannedPlayer(
UInt32 uniqueIdentifier,
string name,
Either<Address, AccountId> addressOrAccountId,
string reason,
DateTime? expiration)
{
this.Name = name;
this.EndPoint = endPoint;
this.SteamID = steamID;
ParseEndPointAsSteamId();
this.IsRangeBan = isRangeBan;
this.AddressOrAccountId = addressOrAccountId;
this.UniqueIdentifier = uniqueIdentifier;
this.Reason = reason;
this.ExpirationTime = expiration;
}
}
public partial class BanList
partial class BanList
{
private GUIComponent banFrame;
@@ -31,8 +31,7 @@ namespace Barotrauma.Networking
get { return banFrame; }
}
public List<UInt16> localRemovedBans = new List<UInt16>();
public List<UInt16> localRangeBans = new List<UInt16>();
public List<UInt32> localRemovedBans = new List<UInt32>();
private void RecreateBanFrame()
{
@@ -71,28 +70,22 @@ namespace Barotrauma.Networking
RelativeSpacing = 0.02f
};
string endPoint = bannedPlayer.EndPoint;
if (localRangeBans.Contains(bannedPlayer.UniqueIdentifier)) endPoint = ToRange(endPoint);
GUITextBlock textBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.0f), topArea.RectTransform),
bannedPlayer.Name + " (" + endPoint + ")");
textBlock.RectTransform.MinSize = new Point(textBlock.Rect.Width, 0);
var addressOrAccountId = bannedPlayer.AddressOrAccountId;
GUITextBlock textBlock = new GUITextBlock(
new RectTransform(new Vector2(0.5f, 1.0f), topArea.RectTransform),
bannedPlayer.Name + " (" + addressOrAccountId + ")") { CanBeFocused = true };
textBlock.RectTransform.MinSize = new Point(
(int)textBlock.Font.MeasureString(textBlock.Text.SanitizedValue).X, 0);
if (bannedPlayer.EndPoint.IndexOf(".x") <= -1)
{
var rangeBanButton = new GUIButton(new RectTransform(new Vector2(0.25f, 0.4f), topArea.RectTransform),
TextManager.Get("BanRange"), style: "GUIButtonSmall")
{
UserData = bannedPlayer,
OnClicked = RangeBan
};
}
var removeButton = new GUIButton(new RectTransform(new Vector2(0.2f, 0.4f), topArea.RectTransform),
TextManager.Get("BanListRemove"), style: "GUIButtonSmall")
{
UserData = bannedPlayer,
OnClicked = RemoveBan
};
topArea.RectTransform.MinSize = new Point(0, (int)topArea.RectTransform.Children.Max(c => c.Rect.Height * 1.25f));
topArea.RectTransform.MinSize = new Point(0, (int)(removeButton.Rect.Height * 1.25f));
topArea.ForceLayoutRecalculation();
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedPlayerFrame.RectTransform),
bannedPlayer.ExpirationTime == null ?
@@ -127,19 +120,6 @@ namespace Barotrauma.Networking
return true;
}
private bool RangeBan(GUIButton button, object obj)
{
BannedPlayer banned = obj as BannedPlayer;
if (banned == null) { return false; }
localRangeBans.Add(banned.UniqueIdentifier);
RecreateBanFrame();
GameMain.Client?.ServerSettings?.ClientAdminWrite(ServerSettings.NetFlags.Properties);
return true;
}
public void ClientAdminRead(IReadMessage incMsg)
{
@@ -159,8 +139,7 @@ namespace Barotrauma.Networking
for (int i = 0; i < (int)bannedPlayerCount; i++)
{
string name = incMsg.ReadString();
UInt16 uniqueIdentifier = incMsg.ReadUInt16();
bool isRangeBan = incMsg.ReadBoolean();
UInt32 uniqueIdentifier = incMsg.ReadUInt32();
bool includesExpiration = incMsg.ReadBoolean();
incMsg.ReadPadBits();
@@ -173,19 +152,30 @@ namespace Barotrauma.Networking
string reason = incMsg.ReadString();
string endPoint = "";
UInt64 steamID = 0;
Either<Address, AccountId> addressOrAccountId;
if (isOwner)
{
endPoint = incMsg.ReadString();
steamID = incMsg.ReadUInt64();
bool isAddress = incMsg.ReadBoolean();
incMsg.ReadPadBits();
string str = incMsg.ReadString();
if (isAddress && Address.Parse(str).TryUnwrap(out var address))
{
addressOrAccountId = address;
}
else if (AccountId.Parse(str).TryUnwrap(out var accountId))
{
addressOrAccountId = accountId;
}
else
{
continue;
}
}
else
{
endPoint = "Endpoint concealed by host";
steamID = 0;
addressOrAccountId = new UnknownAddress();
}
bannedPlayers.Add(new BannedPlayer(name, uniqueIdentifier, isRangeBan, endPoint, steamID, reason, expiration));
bannedPlayers.Add(new BannedPlayer(uniqueIdentifier, name, addressOrAccountId, reason, expiration));
}
if (banFrame != null)
@@ -198,20 +188,13 @@ namespace Barotrauma.Networking
public void ClientAdminWrite(IWriteMessage outMsg)
{
outMsg.Write((UInt16)localRemovedBans.Count);
foreach (UInt16 uniqueId in localRemovedBans)
{
outMsg.Write(uniqueId);
}
outMsg.Write((UInt16)localRangeBans.Count);
foreach (UInt16 uniqueId in localRangeBans)
outMsg.WriteVariableUInt32((UInt32)localRemovedBans.Count);
foreach (UInt32 uniqueId in localRemovedBans)
{
outMsg.Write(uniqueId);
}
localRemovedBans.Clear();
localRangeBans.Clear();
}
}
}
@@ -35,8 +35,9 @@ namespace Barotrauma.Networking
bool hasSenderClient = msg.ReadBoolean();
if (hasSenderClient)
{
UInt64 clientId = msg.ReadUInt64();
senderClient = GameMain.Client.ConnectedClients.Find(c => c.SteamID == clientId || c.ID == clientId);
string userId = msg.ReadString();
senderClient = GameMain.Client.ConnectedClients.Find(c
=> c.SessionOrAccountIdMatches(userId));
if (senderClient != null) { senderName = senderClient.Name; }
}
bool hasSenderCharacter = msg.ReadBoolean();
@@ -72,8 +72,8 @@ namespace Barotrauma.Networking
partial void InitProjSpecific()
{
VoipQueue = null; VoipSound = null;
if (ID == GameMain.Client.ID) return;
VoipQueue = new VoipQueue(ID, false, true);
if (SessionId == GameMain.Client.SessionId) { return; }
VoipQueue = new VoipQueue(SessionId, canSend: false, canReceive: true);
GameMain.Client?.VoipClient?.RegisterQueue(VoipQueue);
VoipSound = null;
}
@@ -206,7 +206,7 @@ namespace Barotrauma.Networking
case (byte)FileTransferMessageType.Initiate:
{
byte transferId = inc.ReadByte();
var existingTransfer = activeTransfers.Find(t => t.Connection.EndpointMatches(t.Connection.EndPointString) && t.ID == transferId);
var existingTransfer = activeTransfers.Find(t => t.Connection.EndpointMatches(t.Connection.Endpoint) && t.ID == transferId);
finishedTransfers.RemoveAll(t => t.transferId == transferId);
byte fileType = inc.ReadByte();
//ushort chunkLen = inc.ReadUInt16();
@@ -329,7 +329,7 @@ namespace Barotrauma.Networking
{
byte transferId = inc.ReadByte();
var activeTransfer = activeTransfers.Find(t => t.Connection.EndpointMatches(t.Connection.EndPointString) && t.ID == transferId);
var activeTransfer = activeTransfers.Find(t => t.Connection.EndpointMatches(t.Connection.Endpoint) && t.ID == transferId);
if (activeTransfer == null)
{
//it's possible for the server to send some extra data
@@ -406,7 +406,7 @@ namespace Barotrauma.Networking
case (byte)FileTransferMessageType.Cancel:
{
byte transferId = inc.ReadByte();
var matchingTransfer = activeTransfers.Find(t => t.Connection.EndpointMatches(t.Connection.EndPointString) && t.ID == transferId);
var matchingTransfer = activeTransfers.Find(t => t.Connection.EndpointMatches(t.Connection.Endpoint) && t.ID == transferId);
if (matchingTransfer != null)
{
new GUIMessageBox("File transfer cancelled", "The server has cancelled the transfer of the file \"" + matchingTransfer.FileName + "\".");
@@ -1,18 +1,16 @@
using Barotrauma.Items.Components;
using Barotrauma.Extensions;
using Barotrauma.IO;
using Barotrauma.Items.Components;
using Barotrauma.Steam;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using Barotrauma.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using Barotrauma.Extensions;
using Microsoft.Xna.Framework.Input;
namespace Barotrauma.Networking
{
@@ -23,14 +21,9 @@ namespace Barotrauma.Networking
get { return true; }
}
private string name;
private UInt16 nameId = 0;
public string Name
{
get { return name; }
}
public string Name { get; private set; }
public string PendingName = string.Empty;
@@ -38,7 +31,7 @@ namespace Barotrauma.Networking
{
value = value.Replace(":", "").Replace(";", "");
if (string.IsNullOrEmpty(value)) { return; }
name = value;
Name = value;
nameId++;
}
@@ -89,13 +82,11 @@ namespace Barotrauma.Networking
public bool RoundStarting => roundInitStatus == RoundInitStatus.Starting || roundInitStatus == RoundInitStatus.WaitingForStartGameFinalize;
private byte myID;
private readonly List<Client> otherClients;
public readonly List<SubmarineInfo> ServerSubmarines = new List<SubmarineInfo>();
private string serverIP, serverName;
public string ServerName { get; private set; }
private bool allowReconnect;
private bool requiresPw;
@@ -129,10 +120,7 @@ namespace Barotrauma.Networking
public LocalizedString TraitorFirstObjective;
public TraitorMissionPrefab TraitorMission = null;
public byte ID
{
get { return myID; }
}
public byte SessionId { get; private set; }
public VoipClient VoipClient
{
@@ -140,7 +128,7 @@ namespace Barotrauma.Networking
private set;
}
public override List<Client> ConnectedClients
public override IReadOnlyList<Client> ConnectedClients
{
get
{
@@ -175,14 +163,10 @@ namespace Barotrauma.Networking
set;
}
private readonly object serverEndpoint;
private readonly int ownerKey;
private readonly bool steamP2POwner;
private readonly Endpoint serverEndpoint;
private readonly Option<int> ownerKey;
public bool IsServerOwner
{
get { return ownerKey > 0 || steamP2POwner; }
}
public bool IsServerOwner => ownerKey.IsSome();
internal readonly struct PermissionChangedEvent
{
@@ -198,11 +182,10 @@ namespace Barotrauma.Networking
public readonly NamedEvent<PermissionChangedEvent> OnPermissionChanged = new NamedEvent<PermissionChangedEvent>();
public GameClient(string newName, string ip, UInt64 steamId, string serverName = null, int ownerKey = 0, bool steamP2POwner = false)
public GameClient(string newName, Endpoint endpoint, string serverName, Option<int> ownerKey)
{
//TODO: gui stuff should probably not be here?
this.ownerKey = ownerKey;
this.steamP2POwner = steamP2POwner;
roundInitStatus = RoundInitStatus.NotStarted;
@@ -280,7 +263,7 @@ namespace Barotrauma.Networking
fileReceiver.OnFinished += OnFileReceived;
fileReceiver.OnTransferFailed += OnTransferFailed;
characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, name, null)
characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, Name, originalName: null)
{
Job = null
};
@@ -290,15 +273,8 @@ namespace Barotrauma.Networking
serverSettings = new ServerSettings(this, "Server", 0, 0, 0, false, false);
Voting = new Voting();
if (steamId == 0)
{
serverEndpoint = ip;
}
else
{
serverEndpoint = steamId;
}
ConnectToServer(serverEndpoint, serverName);
serverEndpoint = endpoint;
InitiateServerJoin(serverName);
//ServerLog = new ServerLog("");
@@ -306,7 +282,7 @@ namespace Barotrauma.Networking
GameMain.ResetNetLobbyScreen();
}
private void ConnectToServer(object endpoint, string hostName)
private void InitiateServerJoin(string hostName)
{
LastClientListUpdateID = 0;
@@ -315,7 +291,7 @@ namespace Barotrauma.Networking
GameMain.NetLobbyScreen.RemovePlayer(c);
c.Dispose();
}
ConnectedClients.Clear();
otherClients.Clear();
chatBox.InputBox.Enabled = false;
if (GameMain.NetLobbyScreen?.ChatInput != null)
@@ -323,102 +299,48 @@ namespace Barotrauma.Networking
GameMain.NetLobbyScreen.ChatInput.Enabled = false;
}
serverName = hostName;
ServerName = hostName;
myCharacter = Character.Controlled;
ChatMessage.LastID = 0;
clientPeer?.Close();
clientPeer = null;
object translatedEndpoint = null;
if (endpoint is string hostIP)
{
int port;
string[] address = hostIP.Split(':');
if (address.Length == 1)
{
serverIP = hostIP;
port = NetConfig.DefaultPort;
}
else
{
serverIP = string.Join(":", address.Take(address.Length - 1));
if (!int.TryParse(address[address.Length - 1], out port))
{
DebugConsole.ThrowError("Invalid port: " + address[address.Length - 1] + "!");
port = NetConfig.DefaultPort;
}
}
clientPeer = new LidgrenClientPeer(Name);
System.Net.IPEndPoint IPEndPoint = null;
try
{
IPEndPoint = new System.Net.IPEndPoint(Lidgren.Network.NetUtility.Resolve(serverIP), port);
}
catch
{
new GUIMessageBox(TextManager.Get("CouldNotConnectToServer"),
TextManager.GetWithVariables("InvalidIPAddress", ("[serverip]", serverIP), ("[port]", port.ToString())));
return;
}
translatedEndpoint = IPEndPoint;
}
else if (endpoint is UInt64)
{
if (steamP2POwner)
{
clientPeer = new SteamP2POwnerPeer(Name);
}
else
{
clientPeer = new SteamP2PClientPeer(Name);
}
translatedEndpoint = endpoint;
}
clientPeer.OnDisconnect = OnDisconnect;
clientPeer.OnDisconnectMessageReceived = HandleDisconnectMessage;
clientPeer.OnInitializationComplete = OnConnectionInitializationComplete;
clientPeer.OnRequestPassword = (int salt, int retries) =>
{
if (pwRetries != retries)
{
wrongPassword = retries > 0;
requiresPw = true;
}
pwRetries = retries;
};
clientPeer.OnMessageReceived = ReadDataMessage;
// Connect client, to endpoint previously requested from user
try
{
clientPeer.Start(translatedEndpoint, ownerKey);
}
catch (Exception e)
{
DebugConsole.ThrowError("Couldn't connect to " + endpoint.ToString() + ". Error message: " + e.Message);
Disconnect();
chatBox.InputBox.Enabled = true;
if (GameMain.NetLobbyScreen?.ChatInput != null)
{
GameMain.NetLobbyScreen.ChatInput.Enabled = true;
}
GameMain.ServerListScreen.Select();
return;
}
clientPeer = CreateNetPeer();
clientPeer.Start();
updateInterval = new TimeSpan(0, 0, 0, 0, 150);
CoroutineManager.StartCoroutine(WaitForStartingInfo(), "WaitForStartingInfo");
}
private ClientPeer CreateNetPeer()
{
Networking.ClientPeer.Callbacks callbacks = new ClientPeer.Callbacks(
ReadDataMessage,
OnClientPeerDisconnect,
HandleDisconnectMessage,
(int salt, int retries) =>
{
if (pwRetries != retries)
{
wrongPassword = retries > 0;
requiresPw = true;
}
pwRetries = retries;
},
OnConnectionInitializationComplete);
return serverEndpoint switch
{
LidgrenEndpoint lidgrenEndpoint => new LidgrenClientPeer(lidgrenEndpoint, callbacks, ownerKey),
SteamP2PEndpoint _ when ownerKey is Some<int> { Value: var key } => new SteamP2POwnerPeer(callbacks, key),
SteamP2PEndpoint steamP2PServerEndpoint when ownerKey.IsNone() => new SteamP2PClientPeer(steamP2PServerEndpoint, callbacks),
_ => throw new ArgumentOutOfRangeException()
};
}
private bool ReturnToPreviousMenu(GUIButton button, object obj)
{
Disconnect();
Quit();
Submarine.Unload();
GameMain.Client = null;
@@ -442,7 +364,7 @@ namespace Barotrauma.Networking
{
ChildServerRelay.ShutDown();
connectCancelled = true;
Disconnect();
Quit();
}
private bool wrongPassword;
@@ -467,14 +389,13 @@ namespace Barotrauma.Networking
{
if (reconnectBox == null && waitInServerQueueBox == null)
{
string serverDisplayName = serverName;
if (string.IsNullOrEmpty(serverDisplayName)) { serverDisplayName = serverIP; }
string serverDisplayName = ServerName;
if (string.IsNullOrEmpty(serverDisplayName) && clientPeer?.ServerConnection is SteamP2PConnection steamConnection)
{
serverDisplayName = steamConnection.SteamID.ToString();
if (SteamManager.IsInitialized)
if (SteamManager.IsInitialized && steamConnection.AccountInfo.AccountId.TryUnwrap(out var accountId) && accountId is SteamId steamId)
{
string steamUserName = Steamworks.SteamFriends.GetFriendPersonaName(steamConnection.SteamID);
serverDisplayName = steamId.ToString();
string steamUserName = Steamworks.SteamFriends.GetFriendPersonaName(steamId.Value);
if (!string.IsNullOrEmpty(steamUserName) && steamUserName != "[unknown]")
{
serverDisplayName = steamUserName;
@@ -604,7 +525,7 @@ namespace Barotrauma.Networking
{
if (VoipCapture.Instance.LastEnqueueAudio > DateTime.Now - new TimeSpan(0, 0, 0, 0, milliseconds: 100))
{
var myClient = ConnectedClients.Find(c => c.ID == ID);
var myClient = ConnectedClients.Find(c => c.SessionId == SessionId);
if (Screen.Selected == GameMain.NetLobbyScreen)
{
GameMain.NetLobbyScreen.SetPlayerSpeaking(myClient);
@@ -645,7 +566,7 @@ namespace Barotrauma.Networking
GameAnalyticsManager.AddErrorEventOnce("GameClient.Update:CheckServerMessagesException" + e.TargetSite.ToString(), GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
DebugConsole.ThrowError("Error while reading a message from server.", e);
new GUIMessageBox(TextManager.Get("Error"), TextManager.GetWithVariables("MessageReadError", ("[message]", e.Message), ("[targetsite]", e.TargetSite.ToString())));
Disconnect();
Quit();
GameMain.ServerListScreen.Select();
return;
}
@@ -688,7 +609,7 @@ namespace Barotrauma.Networking
{
if (ChildServerRelay.Process?.HasExited ?? true)
{
Disconnect();
Quit();
if (!GUIMessageBox.MessageBoxes.Any(mb => (mb as GUIMessageBox)?.Text?.Text == ChildServerRelay.CrashMessage))
{
var msgBox = new GUIMessageBox(TextManager.Get("ConnectionLost"), ChildServerRelay.CrashMessage);
@@ -769,7 +690,7 @@ namespace Barotrauma.Networking
{
byte clientId = inc.ReadByte();
UInt16 clientPing = inc.ReadUInt16();
Client client = ConnectedClients.Find(c => c.ID == clientId);
Client client = ConnectedClients.Find(c => c.SessionId == clientId);
if (client != null)
{
client.Ping = clientPing;
@@ -1079,16 +1000,15 @@ namespace Barotrauma.Networking
roundInitStatus = RoundInitStatus.Started;
}
private void OnDisconnect(bool disableReconnect)
/// <summary>
/// Fires when the ClientPeer gets disconnected from the server. Does not necessarily mean the client is shutting down, we may still be able to reconnect.
/// </summary>
private void OnClientPeerDisconnect(bool disableReconnect)
{
CoroutineManager.StopCoroutines("WaitForStartingInfo");
reconnectBox?.Close();
reconnectBox = null;
GameMain.ModDownloadScreen.Reset();
ContentPackageManager.EnabledPackages.Restore();
GUI.ClearCursorWait();
if (disableReconnect) { allowReconnect = false; }
@@ -1125,7 +1045,6 @@ namespace Barotrauma.Networking
if (disconnectReason != DisconnectReason.Banned &&
disconnectReason != DisconnectReason.ServerShutdown &&
disconnectReason != DisconnectReason.TooManyFailedLogins &&
disconnectReason != DisconnectReason.NotOnWhitelist &&
disconnectReason != DisconnectReason.MissingContentPackage &&
disconnectReason != DisconnectReason.InvalidVersion)
{
@@ -1197,14 +1116,16 @@ namespace Barotrauma.Networking
reconnectBox?.Close();
reconnectBox = new GUIMessageBox(
TextManager.Get("ConnectionLost"), msg,
new LocalizedString[] { TextManager.Get("Cancel") });
reconnectBox.Buttons[0].OnClicked += (btn, userdata) => { CancelConnect(); return true; };
new LocalizedString[] { TextManager.Get("Cancel") })
{
DisplayInLoadingScreens = true
};
reconnectBox.Buttons[0].OnClicked += ReturnToPreviousMenu;
connected = false;
var prevContentPackages = clientPeer.ServerContentPackages;
//decrement lobby update ID to make sure we update the lobby when we reconnect
GameMain.NetLobbyScreen.LastUpdateID--;
ConnectToServer(serverEndpoint, serverName);
InitiateServerJoin(ServerName);
if (clientPeer != null)
{
//restore the previous list of content packages so we can reconnect immediately without having to recheck that the packages match
@@ -1243,12 +1164,18 @@ namespace Barotrauma.Networking
if (msg == Lidgren.Network.NetConnection.NoResponseMessage)
{
//display a generic "could not connect" popup if the message is Lidgren's "failed to establish connection"
var msgBox = new GUIMessageBox(TextManager.Get("ConnectionFailed"), TextManager.Get(allowReconnect ? "ConnectionLost" : "CouldNotConnectToServer"));
var msgBox = new GUIMessageBox(TextManager.Get("ConnectionFailed"), TextManager.Get(allowReconnect ? "ConnectionLost" : "CouldNotConnectToServer"))
{
DisplayInLoadingScreens = true
};
msgBox.Buttons[0].OnClicked += ReturnToPreviousMenu;
}
else
{
var msgBox = new GUIMessageBox(TextManager.Get(allowReconnect ? "ConnectionLost" : "CouldNotConnectToServer"), msg);
var msgBox = new GUIMessageBox(TextManager.Get(allowReconnect ? "ConnectionLost" : "CouldNotConnectToServer"), msg)
{
DisplayInLoadingScreens = true
};
msgBox.Buttons[0].OnClicked += ReturnToPreviousMenu;
}
@@ -1266,8 +1193,8 @@ namespace Barotrauma.Networking
if (SteamManager.IsInitialized)
{
Steamworks.SteamFriends.ClearRichPresence();
Steamworks.SteamFriends.SetRichPresence("status", "Playing on " + serverName);
Steamworks.SteamFriends.SetRichPresence("connect", "-connect \"" + serverName.Replace("\"", "\\\"") + "\" " + serverEndpoint);
Steamworks.SteamFriends.SetRichPresence("status", "Playing on " + ServerName);
Steamworks.SteamFriends.SetRichPresence("connect", "-connect \"" + ServerName.Replace("\"", "\\\"") + "\" " + serverEndpoint);
}
canStart = true;
@@ -1275,7 +1202,7 @@ namespace Barotrauma.Networking
VoipClient = new VoipClient(this, clientPeer);
if (Screen.Selected != GameMain.GameScreen)
if (Screen.Selected != GameMain.GameScreen && !(Screen.Selected is RoundSummaryScreen))
{
GameMain.ModDownloadScreen.Select();
}
@@ -1312,7 +1239,7 @@ namespace Barotrauma.Networking
{
if (!CoroutineManager.IsCoroutineRunning("WaitForStartingInfo"))
{
ConnectToServer(serverEndpoint, serverName);
InitiateServerJoin(ServerName);
yield return new WaitForSeconds(5.0f);
}
yield return new WaitForSeconds(0.5f);
@@ -1383,15 +1310,15 @@ namespace Barotrauma.Networking
private void ReadPermissions(IReadMessage inc)
{
List<string> permittedConsoleCommands = new List<string>();
byte clientID = inc.ReadByte();
byte clientId = inc.ReadByte();
ClientPermissions permissions = ClientPermissions.None;
List<DebugConsole.Command> permittedCommands = new List<DebugConsole.Command>();
Client.ReadPermissions(inc, out permissions, out permittedCommands);
Client targetClient = ConnectedClients.Find(c => c.ID == clientID);
Client targetClient = ConnectedClients.Find(c => c.SessionId == clientId);
targetClient?.SetPermissions(permissions, permittedCommands);
if (clientID == myID)
if (clientId == SessionId)
{
SetMyPermissions(permissions, permittedCommands.Select(command => command.names[0]));
}
@@ -1923,7 +1850,7 @@ namespace Barotrauma.Networking
private void ReadInitialUpdate(IReadMessage inc)
{
myID = inc.ReadByte();
SessionId = inc.ReadByte();
UInt16 subListCount = inc.ReadUInt16();
ServerSubmarines.Clear();
@@ -1983,22 +1910,22 @@ namespace Barotrauma.Networking
foreach (TempClient tc in tempClients)
{
//see if the client already exists
var existingClient = ConnectedClients.Find(c => c.ID == tc.ID && c.Name == tc.Name);
var existingClient = ConnectedClients.Find(c => c.SessionId == tc.SessionId && c.Name == tc.Name);
if (existingClient == null) //if not, create it
{
existingClient = new Client(tc.Name, tc.ID)
existingClient = new Client(tc.Name, tc.SessionId)
{
SteamID = tc.SteamID,
AccountInfo = tc.AccountInfo,
Muted = tc.Muted,
InGame = tc.InGame,
AllowKicking = tc.AllowKicking,
IsOwner = tc.IsOwner
};
ConnectedClients.Add(existingClient);
otherClients.Add(existingClient);
refreshCampaignUI = true;
GameMain.NetLobbyScreen.AddPlayer(existingClient);
}
existingClient.NameID = tc.NameID;
existingClient.NameId = tc.NameId;
existingClient.PreferredJob = tc.PreferredJob;
existingClient.PreferredTeam = tc.PreferredTeam;
existingClient.Character = null;
@@ -2009,22 +1936,22 @@ namespace Barotrauma.Networking
existingClient.AllowKicking = tc.AllowKicking;
existingClient.IsDownloading = tc.IsDownloading;
GameMain.NetLobbyScreen.SetPlayerNameAndJobPreference(existingClient);
if (Screen.Selected != GameMain.NetLobbyScreen && tc.CharacterID > 0)
if (Screen.Selected != GameMain.NetLobbyScreen && tc.CharacterId > 0)
{
existingClient.CharacterID = tc.CharacterID;
existingClient.CharacterID = tc.CharacterId;
}
if (existingClient.ID == myID)
if (existingClient.SessionId == SessionId)
{
existingClient.SetPermissions(permissions, permittedConsoleCommands);
if (!NetIdUtils.IdMoreRecent(nameId, tc.NameID))
if (!NetIdUtils.IdMoreRecent(nameId, tc.NameId))
{
name = tc.Name;
nameId = tc.NameID;
Name = tc.Name;
nameId = tc.NameId;
}
if (GameMain.NetLobbyScreen.CharacterNameBox != null &&
!GameMain.NetLobbyScreen.CharacterNameBox.Selected)
{
GameMain.NetLobbyScreen.CharacterNameBox.Text = name;
GameMain.NetLobbyScreen.CharacterNameBox.Text = Name;
}
}
currentClients.Add(existingClient);
@@ -2035,14 +1962,14 @@ namespace Barotrauma.Networking
if (!currentClients.Contains(ConnectedClients[i]))
{
GameMain.NetLobbyScreen.RemovePlayer(ConnectedClients[i]);
ConnectedClients[i].Dispose();
ConnectedClients.RemoveAt(i);
otherClients[i].Dispose();
otherClients.RemoveAt(i);
refreshCampaignUI = true;
}
}
foreach (Client client in ConnectedClients)
{
int index = previouslyConnectedClients.FindIndex(c => c.ID == client.ID);
int index = previouslyConnectedClients.FindIndex(c => c.SessionId == client.SessionId);
if (index < 0)
{
if (previouslyConnectedClients.Count > 100)
@@ -2405,7 +2332,7 @@ namespace Barotrauma.Networking
outmsg.Write(ChatMessage.LastID);
outmsg.Write(LastClientListUpdateID);
outmsg.Write(nameId);
outmsg.Write(name);
outmsg.Write(Name);
var jobPreferences = GameMain.NetLobbyScreen.JobPreferences;
if (jobPreferences.Count > 0)
{
@@ -2519,7 +2446,7 @@ namespace Barotrauma.Networking
if (clientPeer?.ServerConnection == null) { return; }
ChatMessage chatMessage = ChatMessage.Create(
gameStarted && myCharacter != null ? myCharacter.Name : name,
gameStarted && myCharacter != null ? myCharacter.Name : Name,
message,
type,
gameStarted && myCharacter != null ? myCharacter : null);
@@ -2761,7 +2688,7 @@ namespace Barotrauma.Networking
return false;
}
public override void Disconnect()
public override void Quit()
{
allowReconnect = false;
@@ -2770,6 +2697,9 @@ namespace Barotrauma.Networking
SteamManager.LeaveLobby();
}
GameMain.ModDownloadScreen.Reset();
ContentPackageManager.EnabledPackages.Restore();
CampaignMode.StartRoundCancellationToken?.Cancel();
clientPeer?.Close();
@@ -2864,7 +2794,7 @@ namespace Barotrauma.Networking
public void VoteForKick(Client votedClient)
{
if (votedClient == null) { return; }
votedClient.AddKickVote(ConnectedClients.FirstOrDefault(c => c.ID == myID));
votedClient.AddKickVote(ConnectedClients.FirstOrDefault(c => c.SessionId == SessionId));
Vote(VoteType.Kick, votedClient);
}
@@ -2918,26 +2848,35 @@ namespace Barotrauma.Networking
clientPeer.Send(msg, DeliveryMethod.Reliable);
}
public override void BanPlayer(string kickedName, string reason, bool range = false, TimeSpan? duration = null)
public override void BanPlayer(string kickedName, string reason, TimeSpan? duration = null)
{
IWriteMessage msg = new WriteOnlyMessage();
msg.Write((byte)ClientPacketHeader.SERVER_COMMAND);
msg.Write((UInt16)ClientPermissions.Ban);
msg.Write(kickedName);
msg.Write(reason);
msg.Write(range);
msg.Write(duration.HasValue ? duration.Value.TotalSeconds : 0.0); //0 = permaban
clientPeer.Send(msg, DeliveryMethod.Reliable);
}
public override void UnbanPlayer(string playerName, string playerIP)
public override void UnbanPlayer(string playerName)
{
IWriteMessage msg = new WriteOnlyMessage();
msg.Write((byte)ClientPacketHeader.SERVER_COMMAND);
msg.Write((UInt16)ClientPermissions.Unban);
msg.Write(string.IsNullOrEmpty(playerName) ? "" : playerName);
msg.Write(string.IsNullOrEmpty(playerIP) ? "" : playerIP);
msg.Write(true); msg.WritePadBits();
msg.Write(playerName);
clientPeer.Send(msg, DeliveryMethod.Reliable);
}
public override void UnbanPlayer(Endpoint endpoint)
{
IWriteMessage msg = new WriteOnlyMessage();
msg.Write((byte)ClientPacketHeader.SERVER_COMMAND);
msg.Write((UInt16)ClientPermissions.Unban);
msg.Write(false); msg.WritePadBits();
msg.Write(endpoint.StringRepresentation);
clientPeer.Send(msg, DeliveryMethod.Reliable);
}
@@ -3470,7 +3409,7 @@ namespace Barotrauma.Networking
public virtual bool SelectCrewClient(Client client, GUIComponent frame)
{
if (client == null || client.ID == ID) { return false; }
if (client == null || client.SessionId == SessionId) { return false; }
CreateSelectionRelatedButtons(client, frame);
return true;
}
@@ -3543,12 +3482,12 @@ namespace Barotrauma.Networking
};
if (GameMain.NetworkMember.ConnectedClients != null)
{
kickVoteButton.Enabled = !client.HasKickVoteFromID(myID);
kickVoteButton.Enabled = !client.HasKickVoteFromSessionId(SessionId);
}
}
}
public void CreateKickReasonPrompt(string clientName, bool ban, bool rangeBan = false)
public void CreateKickReasonPrompt(string clientName, bool ban)
{
var banReasonPrompt = new GUIMessageBox(
TextManager.Get(ban ? "BanReasonPrompt" : "KickReasonPrompt"),
@@ -3609,11 +3548,11 @@ namespace Barotrauma.Networking
if (!permaBanTickBox.Selected)
{
TimeSpan banDuration = new TimeSpan(durationInputDays.IntValue, durationInputHours.IntValue, 0, 0);
BanPlayer(clientName, banReasonBox.Text, ban, banDuration);
BanPlayer(clientName, banReasonBox.Text, banDuration);
}
else
{
BanPlayer(clientName, banReasonBox.Text, range: rangeBan);
BanPlayer(clientName, banReasonBox.Text);
}
}
else
@@ -3626,7 +3565,7 @@ namespace Barotrauma.Networking
banReasonPrompt.Buttons[1].OnClicked += banReasonPrompt.Close;
}
public void ReportError(ClientNetError error, UInt16 expectedID = 0, UInt16 eventID = 0, UInt16 entityID = 0)
public void ReportError(ClientNetError error, UInt16 expectedId = 0, UInt16 eventId = 0, UInt16 entityId = 0)
{
IWriteMessage outMsg = new WriteOnlyMessage();
outMsg.Write((byte)ClientPacketHeader.ERROR);
@@ -3634,12 +3573,12 @@ namespace Barotrauma.Networking
switch (error)
{
case ClientNetError.MISSING_EVENT:
outMsg.Write(expectedID);
outMsg.Write(eventID);
outMsg.Write(expectedId);
outMsg.Write(eventId);
break;
case ClientNetError.MISSING_ENTITY:
outMsg.Write(eventID);
outMsg.Write(entityID);
outMsg.Write(eventId);
outMsg.Write(entityId);
outMsg.Write((byte)Submarine.Loaded.Count);
foreach (Submarine sub in Submarine.Loaded)
{
@@ -3651,7 +3590,7 @@ namespace Barotrauma.Networking
if (!eventErrorWritten)
{
WriteEventErrorData(error, expectedID, eventID, entityID);
WriteEventErrorData(error, expectedId, eventId, entityId);
eventErrorWritten = true;
}
}
@@ -203,7 +203,7 @@ namespace Barotrauma.Networking
DebugConsole.NewMessage(
"Received msg " + thisEventID + ", entity " + entityID + " not found",
GUIStyle.Red);
GameMain.Client.ReportError(ClientNetError.MISSING_ENTITY, eventID: thisEventID, entityID: entityID);
GameMain.Client.ReportError(ClientNetError.MISSING_ENTITY, eventId: thisEventID, entityId: entityID);
return false;
}
@@ -1,11 +1,9 @@
using Barotrauma.Extensions;
#nullable enable
using Barotrauma.Steam;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Barotrauma.Networking
{
@@ -18,7 +16,7 @@ namespace Barotrauma.Networking
public readonly UInt64 WorkshopId;
public readonly DateTime InstallTime;
public RegularPackage RegularPackage
public RegularPackage? RegularPackage
{
get
{
@@ -26,7 +24,7 @@ namespace Barotrauma.Networking
}
}
public CorePackage CorePackage
public CorePackage? CorePackage
{
get
{
@@ -34,8 +32,8 @@ namespace Barotrauma.Networking
}
}
public ContentPackage ContentPackage
=> (ContentPackage)RegularPackage ?? CorePackage;
public ContentPackage? ContentPackage
=> (ContentPackage?)RegularPackage ?? CorePackage;
public string GetPackageStr()
@@ -58,21 +56,44 @@ namespace Barotrauma.Networking
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 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;
}
}
protected readonly Callbacks callbacks;
public readonly Endpoint ServerEndpoint;
public NetworkConnection? ServerConnection { get; protected set; }
protected readonly bool isOwner;
protected readonly Option<int> ownerKey;
public ClientPeer(Endpoint serverEndpoint, Callbacks callbacks, Option<int> ownerKey)
{
ServerEndpoint = serverEndpoint;
this.callbacks = callbacks;
this.ownerKey = ownerKey;
isOwner = ownerKey.IsSome();
}
public MessageCallback OnMessageReceived;
public DisconnectCallback OnDisconnect;
public DisconnectMessageCallback OnDisconnectMessageReceived;
public PasswordCallback OnRequestPassword;
public InitializationCompleteCallback OnInitializationComplete;
public string Name;
public string Version { get; protected set; }
public NetworkConnection ServerConnection { get; protected set; }
public abstract void Start(object endPoint, int ownerKey);
public abstract void Close(string msg = null, bool disableReconnect = false);
public abstract void Start();
public abstract void Close(string? msg = null, bool disableReconnect = false);
public abstract void Update(float deltaTime);
public abstract void Send(IWriteMessage msg, DeliveryMethod deliveryMethod, bool compressPastThreshold = true);
public abstract void SendPassword(string password);
@@ -80,10 +101,9 @@ namespace Barotrauma.Networking
protected abstract void SendMsgInternal(DeliveryMethod deliveryMethod, IWriteMessage msg);
protected ConnectionInitialization initializationStep;
protected bool contentPackageOrderReceived;
protected int ownerKey = 0;
public bool ContentPackageOrderReceived { get; protected set; }
protected int passwordSalt;
protected Steamworks.AuthTicket steamAuthTicket;
protected Steamworks.AuthTicket? steamAuthTicket;
protected void ReadConnectionInitializationStep(IReadMessage inc)
{
ConnectionInitialization step = (ConnectionInitialization)inc.ReadByte();
@@ -97,9 +117,9 @@ namespace Barotrauma.Networking
outMsg = new WriteOnlyMessage();
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
outMsg.Write((byte)ConnectionInitialization.SteamTicketAndVersion);
outMsg.Write(Name);
outMsg.Write(ownerKey);
outMsg.Write(SteamManager.GetSteamID());
outMsg.Write(GameMain.Client.Name);
outMsg.Write(ownerKey.Fallback(0));
outMsg.Write(SteamManager.GetSteamId().Select(steamId => steamId.Value).Fallback(0));
if (steamAuthTicket == null)
{
outMsg.Write((UInt16)0);
@@ -122,8 +142,6 @@ namespace Barotrauma.Networking
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
outMsg.Write((byte)ConnectionInitialization.ContentPackageOrder);
string serverName = inc.ReadString();
UInt32 packageCount = inc.ReadVariableUInt32();
List<ServerContentPackage> serverPackages = new List<ServerContentPackage>();
for (int i = 0; i < packageCount; i++)
@@ -139,9 +157,16 @@ namespace Barotrauma.Networking
serverPackages.Add(pkg);
}
if (!contentPackageOrderReceived)
if (!ContentPackageOrderReceived)
{
ServerContentPackages = serverPackages.ToImmutableArray();
if (serverPackages.Count == 0)
{
string errorMsg = "Error in ContentPackageOrder message: list of content packages enabled on the server was empty.";
GameAnalyticsManager.AddErrorEventOnce("ClientPeer.ReadConnectionInitializationStep:NoContentPackages", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
DebugConsole.ThrowError(errorMsg);
}
ContentPackageOrderReceived = true;
SendMsgInternal(DeliveryMethod.Reliable, outMsg);
}
break;
@@ -158,7 +183,7 @@ namespace Barotrauma.Networking
{
retries = inc.ReadInt32();
}
OnRequestPassword?.Invoke(passwordSalt, retries);
callbacks.OnRequestPassword.Invoke(passwordSalt, retries);
break;
}
}
@@ -1,10 +1,8 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using Barotrauma.Steam;
using Lidgren.Network;
using Barotrauma.Steam;
using System.Linq;
using System;
using System.Collections.Generic;
using System.Text;
namespace Barotrauma.Networking
{
@@ -16,39 +14,42 @@ namespace Barotrauma.Networking
List<NetIncomingMessage> incomingLidgrenMessages;
public LidgrenClientPeer(string name)
private LidgrenEndpoint lidgrenEndpoint
=> ServerConnection is LidgrenConnection { Endpoint: LidgrenEndpoint result }
? result
: throw new InvalidOperationException();
public LidgrenClientPeer(LidgrenEndpoint endpoint, Callbacks callbacks, Option<int> ownerKey) : base(endpoint, callbacks, ownerKey)
{
ServerConnection = null;
Name = name;
netClient = null;
isActive = false;
}
public override void Start(object endPoint, int ownerKey)
public override void Start()
{
if (isActive) { return; }
this.ownerKey = ownerKey;
contentPackageOrderReceived = false;
ContentPackageOrderReceived = false;
netPeerConfiguration = new NetPeerConfiguration("barotrauma")
{
UseDualModeSockets = GameSettings.CurrentConfig.UseDualModeSockets
};
netPeerConfiguration.DisableMessageType(NetIncomingMessageType.DebugMessage | NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt
| NetIncomingMessageType.ErrorMessage | NetIncomingMessageType.Error);
netPeerConfiguration.DisableMessageType(
NetIncomingMessageType.DebugMessage
| NetIncomingMessageType.WarningMessage
| NetIncomingMessageType.Receipt
| NetIncomingMessageType.ErrorMessage
| NetIncomingMessageType.Error);
netClient = new NetClient(netPeerConfiguration);
if (SteamManager.IsInitialized)
{
steamAuthTicket = SteamManager.GetAuthSessionTicket();
//TODO: wait for GetAuthSessionTicketResponse_t
if (steamAuthTicket == null)
{
throw new Exception("GetAuthSessionTicket returned null");
@@ -59,7 +60,7 @@ namespace Barotrauma.Networking
initializationStep = ConnectionInitialization.SteamTicketAndVersion;
if (!(endPoint is IPEndPoint ipEndPoint))
if (!(ServerEndpoint is LidgrenEndpoint lidgrenEndpoint))
{
throw new InvalidCastException("endPoint is not IPEndPoint");
}
@@ -69,7 +70,10 @@ namespace Barotrauma.Networking
}
netClient.Start();
ServerConnection = new LidgrenConnection("Server", netClient.Connect(ipEndPoint), 0)
var netConnection = netClient.Connect(lidgrenEndpoint.NetEndpoint);
ServerConnection = new LidgrenConnection(netConnection)
{
Status = NetworkConnectionStatus.Connected
};
@@ -81,7 +85,7 @@ namespace Barotrauma.Networking
{
if (!isActive) { return; }
if (ownerKey != 0 && (ChildServerRelay.Process?.HasExited ?? true))
if (isOwner && !(ChildServerRelay.Process is { HasExited: false }))
{
Close();
var msgBox = new GUIMessageBox(TextManager.Get("ConnectionLost"), ChildServerRelay.CrashMessage);
@@ -97,7 +101,7 @@ namespace Barotrauma.Networking
foreach (NetIncomingMessage inc in incomingLidgrenMessages)
{
if (inc.SenderConnection != (ServerConnection as LidgrenConnection).NetConnection) { continue; }
if (!inc.SenderConnection.RemoteEndPoint.Equals(lidgrenEndpoint.NetEndpoint)) { continue; }
switch (inc.MessageType)
{
@@ -125,12 +129,12 @@ namespace Barotrauma.Networking
{
if (initializationStep != ConnectionInitialization.Success)
{
OnInitializationComplete?.Invoke();
callbacks.OnInitializationComplete.Invoke();
initializationStep = ConnectionInitialization.Success;
}
UInt16 length = inc.ReadUInt16();
IReadMessage msg = new ReadOnlyMessage(inc.Data, packetHeader.IsCompressed(), inc.PositionInBytes, length, ServerConnection);
OnMessageReceived?.Invoke(msg);
callbacks.OnMessageReceived.Invoke(msg);
}
}
@@ -144,7 +148,7 @@ namespace Barotrauma.Networking
case NetConnectionStatus.Disconnected:
string disconnectMsg = inc.ReadString();
Close(disconnectMsg);
OnDisconnectMessageReceived?.Invoke(disconnectMsg);
callbacks.OnDisconnectMessageReceived.Invoke(disconnectMsg);
break;
}
}
@@ -176,7 +180,7 @@ namespace Barotrauma.Networking
netClient.Shutdown(msg ?? TextManager.Get("Disconnecting").Value);
netClient = null;
steamAuthTicket?.Cancel(); steamAuthTicket = null;
OnDisconnect?.Invoke(disableReconnect);
callbacks.OnDisconnect.Invoke(disableReconnect);
}
public override void Send(IWriteMessage msg, DeliveryMethod deliveryMethod, bool compressPastThreshold = true)
@@ -1,17 +1,16 @@
using System;
using Barotrauma.Steam;
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using Barotrauma.Steam;
using System.Text;
using System.Threading;
using Barotrauma.Items.Components;
namespace Barotrauma.Networking
{
class SteamP2PClientPeer : ClientPeer
{
private bool isActive;
private UInt64 hostSteamId;
private readonly SteamId hostSteamId;
private double timeout;
private double heartbeatTimer;
private double connectionStatusTimer;
@@ -21,18 +20,23 @@ namespace Barotrauma.Networking
private List<IReadMessage> incomingInitializationMessages;
private List<IReadMessage> incomingDataMessages;
public SteamP2PClientPeer(string name)
public SteamP2PClientPeer(SteamP2PEndpoint endpoint, Callbacks callbacks) : base(endpoint, callbacks, Option<int>.None())
{
ServerConnection = null;
Name = name;
isActive = false;
if (!(ServerEndpoint is SteamP2PEndpoint steamIdEndpoint))
{
throw new InvalidCastException("endPoint is not SteamId");
}
hostSteamId = steamIdEndpoint.SteamId;
}
public override void Start(object endPoint, int ownerKey)
public override void Start()
{
contentPackageOrderReceived = false;
ContentPackageOrderReceived = false;
steamAuthTicket = SteamManager.GetAuthSessionTicket();
//TODO: wait for GetAuthSessionTicketResponse_t
@@ -42,21 +46,14 @@ namespace Barotrauma.Networking
throw new Exception("GetAuthSessionTicket returned null");
}
if (!(endPoint is UInt64 steamIdEndpoint))
{
throw new InvalidCastException("endPoint is not UInt64");
}
hostSteamId = steamIdEndpoint;
Steamworks.SteamNetworking.ResetActions();
Steamworks.SteamNetworking.OnP2PSessionRequest = OnIncomingConnection;
Steamworks.SteamNetworking.OnP2PConnectionFailed = OnConnectionFailed;
Steamworks.SteamNetworking.AllowP2PPacketRelay(true);
ServerConnection = new SteamP2PConnection("Server", hostSteamId);
ServerConnection.SetOwnerSteamIDIfUnknown(hostSteamId);
ServerConnection = new SteamP2PConnection(hostSteamId);
ServerConnection.SetAccountInfo(new AccountInfo(hostSteamId));
incomingInitializationMessages = new List<IReadMessage>();
incomingDataMessages = new List<IReadMessage>();
@@ -66,7 +63,7 @@ namespace Barotrauma.Networking
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
outMsg.Write((byte)ConnectionInitialization.ConnectionStarted);
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId.Value, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
initializationStep = ConnectionInitialization.SteamTicketAndVersion;
@@ -81,7 +78,7 @@ namespace Barotrauma.Networking
private void OnIncomingConnection(Steamworks.SteamId steamId)
{
if (!isActive) { return; }
if (steamId == hostSteamId)
if (steamId == hostSteamId.Value)
{
Steamworks.SteamNetworking.AcceptP2PSessionWithUser(steamId);
}
@@ -90,23 +87,23 @@ namespace Barotrauma.Networking
initializationStep != ConnectionInitialization.Success)
{
DebugConsole.ThrowError($"Connection from incorrect SteamID was rejected: "+
$"expected {SteamManager.SteamIDUInt64ToString(hostSteamId)}," +
$"got {SteamManager.SteamIDUInt64ToString(steamId)}");
$"expected {hostSteamId}," +
$"got {new SteamId(steamId)}");
}
}
private void OnConnectionFailed(Steamworks.SteamId steamId, Steamworks.P2PSessionError error)
{
if (!isActive) { return; }
if (steamId != hostSteamId) { return; }
if (steamId != hostSteamId.Value) { return; }
Close($"SteamP2P connection failed: {error}");
OnDisconnectMessageReceived?.Invoke($"{DisconnectReason.SteamP2PError}/SteamP2P connection failed: {error}");
callbacks.OnDisconnectMessageReceived.Invoke($"{DisconnectReason.SteamP2PError}/SteamP2P connection failed: {error}");
}
private void OnP2PData(ulong steamId, byte[] data, int dataLength)
{
if (!isActive) { return; }
if (steamId != hostSteamId) { return; }
if (steamId != hostSteamId.Value) { return; }
timeout = Screen.Selected == GameMain.GameScreen ?
NetworkConnection.TimeoutThresholdInGame :
@@ -138,7 +135,7 @@ namespace Barotrauma.Networking
IReadMessage inc = new ReadOnlyMessage(data, false, 1, dataLength - 1, ServerConnection);
string msg = inc.ReadString();
Close(msg);
OnDisconnectMessageReceived?.Invoke(msg);
callbacks.OnDisconnectMessageReceived.Invoke(msg);
}
else
{
@@ -166,18 +163,18 @@ namespace Barotrauma.Networking
connectionStatusTimer -= deltaTime;
if (connectionStatusTimer <= 0.0)
{
var state = Steamworks.SteamNetworking.GetP2PSessionState(hostSteamId);
var state = Steamworks.SteamNetworking.GetP2PSessionState(hostSteamId.Value);
if (state == null)
{
Close("SteamP2P connection could not be established");
OnDisconnectMessageReceived?.Invoke(DisconnectReason.SteamP2PError.ToString());
callbacks.OnDisconnectMessageReceived.Invoke(DisconnectReason.SteamP2PError.ToString());
}
else
{
if (state?.P2PSessionError != Steamworks.P2PSessionError.None)
{
Close($"SteamP2P error code: {state?.P2PSessionError}");
OnDisconnectMessageReceived?.Invoke($"{DisconnectReason.SteamP2PError}/SteamP2P error code: {state?.P2PSessionError}");
callbacks.OnDisconnectMessageReceived.Invoke($"{DisconnectReason.SteamP2PError}/SteamP2P error code: {state?.P2PSessionError}");
}
}
connectionStatusTimer = 1.0f;
@@ -204,7 +201,7 @@ namespace Barotrauma.Networking
outMsg.Write((byte)DeliveryMethod.Unreliable);
outMsg.Write((byte)PacketHeader.IsHeartbeatMessage);
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Unreliable);
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId.Value, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Unreliable);
sentBytes += outMsg.LengthBytes;
heartbeatTimer = 5.0;
@@ -213,7 +210,7 @@ namespace Barotrauma.Networking
if (timeout < 0.0)
{
Close("Timed out");
OnDisconnectMessageReceived?.Invoke(DisconnectReason.SteamP2PTimeOut.ToString());
callbacks.OnDisconnectMessageReceived.Invoke(DisconnectReason.SteamP2PTimeOut.ToString());
return;
}
@@ -221,7 +218,22 @@ namespace Barotrauma.Networking
{
if (incomingDataMessages.Count > 0)
{
OnInitializationComplete?.Invoke();
var incomingMessage = incomingDataMessages.First();
byte incomingHeader = incomingMessage.LengthBytes > 0 ? incomingMessage.PeekByte() : (byte)0;
if (ContentPackageOrderReceived)
{
#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);
DebugConsole.ThrowError(errorMsg);
}
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);
}
callbacks.OnInitializationComplete.Invoke();
initializationStep = ConnectionInitialization.Success;
}
else
@@ -237,7 +249,7 @@ namespace Barotrauma.Networking
{
foreach (IReadMessage inc in incomingDataMessages)
{
OnMessageReceived?.Invoke(inc);
callbacks.OnMessageReceived.Invoke(inc);
}
}
@@ -303,7 +315,7 @@ namespace Barotrauma.Networking
private void Send(byte[] buf, int length, Steamworks.P2PSend sendType)
{
bool successSend = Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, buf, length + 4, 0, sendType);
bool successSend = Steamworks.SteamNetworking.SendP2PPacket(hostSteamId.Value, buf, length + 4, 0, sendType);
sentBytes += length + 4;
if (!successSend)
{
@@ -311,7 +323,7 @@ namespace Barotrauma.Networking
{
DebugConsole.Log("WARNING: message couldn't be sent unreliably, forcing reliable send (" + length.ToString() + " bytes)");
sendType = Steamworks.P2PSend.Reliable;
successSend = Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, buf, length + 4, 0, sendType);
successSend = Steamworks.SteamNetworking.SendP2PPacket(hostSteamId.Value, buf, length + 4, 0, sendType);
sentBytes += length + 4;
}
if (!successSend)
@@ -335,7 +347,7 @@ namespace Barotrauma.Networking
outMsg.Write(saltedPw, 0, saltedPw.Length);
heartbeatTimer = 5.0;
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId.Value, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
}
@@ -354,7 +366,7 @@ namespace Barotrauma.Networking
try
{
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId.Value, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
}
catch (Exception e)
@@ -365,12 +377,11 @@ namespace Barotrauma.Networking
Thread.Sleep(100);
Steamworks.SteamNetworking.ResetActions();
Steamworks.SteamNetworking.CloseP2PSessionWithUser(hostSteamId);
Steamworks.SteamNetworking.CloseP2PSessionWithUser(hostSteamId.Value);
steamAuthTicket?.Cancel(); steamAuthTicket = null;
hostSteamId = 0;
OnDisconnect?.Invoke(disableReconnect);
callbacks.OnDisconnect.Invoke(disableReconnect);
}
protected override void SendMsgInternal(DeliveryMethod deliveryMethod, IWriteMessage msg)
@@ -394,7 +405,7 @@ namespace Barotrauma.Networking
msgToSend.Write(msg.Buffer, 0, msg.LengthBytes);
heartbeatTimer = 5.0;
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, msgToSend.Buffer, msgToSend.LengthBytes, 0, sendType);
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId.Value, msgToSend.Buffer, msgToSend.LengthBytes, 0, sendType);
sentBytes += msg.LengthBytes;
}
@@ -1,7 +1,7 @@
using Barotrauma.Steam;
using Barotrauma.Extensions;
using Barotrauma.Steam;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace Barotrauma.Networking
@@ -10,20 +10,20 @@ namespace Barotrauma.Networking
{
private bool isActive;
private readonly UInt64 selfSteamID;
private UInt64 ownerKey64 => unchecked((UInt64)ownerKey);
private readonly SteamId selfSteamID;
private UInt64 ownerKey64 => unchecked((UInt64)ownerKey.Fallback(0));
private UInt64 ReadSteamId(IReadMessage inc)
=> inc.ReadUInt64() ^ ownerKey64;
private void WriteSteamId(IWriteMessage msg, UInt64 val)
=> msg.Write(val ^ ownerKey64);
private SteamId ReadSteamId(IReadMessage inc)
=> new SteamId(inc.ReadUInt64() ^ ownerKey64);
private void WriteSteamId(IWriteMessage msg, SteamId val)
=> msg.Write(val.Value ^ ownerKey64);
private long sentBytes, receivedBytes;
class RemotePeer
{
public UInt64 SteamID;
public UInt64 OwnerSteamID;
public SteamId SteamId;
public Option<SteamId> OwnerSteamId;
public double? DisconnectTime;
public bool Authenticating;
public bool Authenticated;
@@ -33,12 +33,12 @@ namespace Barotrauma.Networking
public DeliveryMethod DeliveryMethod;
public IWriteMessage Message;
}
public List<UnauthedMessage> UnauthedMessages;
public readonly List<UnauthedMessage> UnauthedMessages;
public RemotePeer(UInt64 steamId)
public RemotePeer(SteamId steamId)
{
SteamID = steamId;
OwnerSteamID = 0;
SteamId = steamId;
OwnerSteamId = Option<SteamId>.None();
DisconnectTime = null;
Authenticating = false;
Authenticated = false;
@@ -49,27 +49,27 @@ namespace Barotrauma.Networking
}
List<RemotePeer> remotePeers;
public SteamP2POwnerPeer(string name)
public SteamP2POwnerPeer(Callbacks callbacks, int ownerKey) : base(new PipeEndpoint(), callbacks, Option<int>.Some(ownerKey))
{
ServerConnection = null;
Name = name;
isActive = false;
selfSteamID = Steam.SteamManager.GetSteamID();
selfSteamID = SteamManager.GetSteamId().TryUnwrap(out var steamId)
? steamId
: throw new InvalidOperationException("Steamworks not initialized");
}
public override void Start(object endPoint, int ownerKey)
public override void Start()
{
if (isActive) { return; }
this.ownerKey = ownerKey;
initializationStep = ConnectionInitialization.SteamTicketAndVersion;
ServerConnection = new PipeConnection(selfSteamID);
ServerConnection.Status = NetworkConnectionStatus.Connected;
ServerConnection = new PipeConnection(selfSteamID)
{
Status = NetworkConnectionStatus.Connected
};
remotePeers = new List<RemotePeer>();
@@ -82,10 +82,10 @@ namespace Barotrauma.Networking
isActive = true;
}
private void OnAuthChange(Steamworks.SteamId steamID, Steamworks.SteamId ownerID, Steamworks.AuthResponse status)
private void OnAuthChange(Steamworks.SteamId steamId, Steamworks.SteamId ownerId, Steamworks.AuthResponse status)
{
RemotePeer remotePeer = remotePeers.Find(p => p.SteamID == steamID);
DebugConsole.Log(steamID + " validation: " + status + ", " + (remotePeer != null));
RemotePeer remotePeer = remotePeers.Find(p => p.SteamId.Value == steamId);
DebugConsole.Log(steamId + " validation: " + status + ", " + (remotePeer != null));
if (remotePeer == null) { return; }
@@ -100,7 +100,7 @@ namespace Barotrauma.Networking
if (status == Steamworks.AuthResponse.OK)
{
remotePeer.OwnerSteamID = ownerID;
remotePeer.OwnerSteamId = Option<SteamId>.Some(new SteamId(ownerId));
remotePeer.Authenticated = true;
remotePeer.Authenticating = false;
foreach (var msg in remotePeer.UnauthedMessages)
@@ -111,7 +111,7 @@ namespace Barotrauma.Networking
//known now
int prevBitPosition = msg.Message.BitPosition;
msg.Message.BitPosition = sizeof(ulong) * 8;
WriteSteamId(msg.Message, ownerID);
WriteSteamId(msg.Message, new SteamId(ownerId));
msg.Message.BitPosition = prevBitPosition;
byte[] msgToSend = (byte[])msg.Message.Buffer.Clone();
Array.Resize(ref msgToSend, msg.Message.LengthBytes);
@@ -130,34 +130,33 @@ namespace Barotrauma.Networking
{
if (!isActive) { return; }
if (!remotePeers.Any(p => p.SteamID == steamId))
if (remotePeers.None(p => p.SteamId.Value == steamId))
{
remotePeers.Add(new RemotePeer(steamId));
remotePeers.Add(new RemotePeer(new SteamId(steamId)));
}
Steamworks.SteamNetworking.AcceptP2PSessionWithUser(steamId); //accept all connections, the server will figure things out later
}
private void OnP2PData(ulong steamId, byte[] data, int dataLength, int channel)
private void OnP2PData(ulong steamId, byte[] data, int dataLength, int _)
{
if (!isActive) { return; }
RemotePeer remotePeer = remotePeers.Find(p => p.SteamID == steamId);
if (remotePeer == null || remotePeer.DisconnectTime != null)
{
return;
}
RemotePeer remotePeer = remotePeers.Find(p => p.SteamId.Value == steamId);
if (remotePeer == null) { return; }
if (remotePeer.DisconnectTime != null) { return; }
IWriteMessage outMsg = new WriteOnlyMessage();
WriteSteamId(outMsg, steamId);
WriteSteamId(outMsg, remotePeer.OwnerSteamID);
var steamUserId = new SteamId(steamId);
WriteSteamId(outMsg, steamUserId);
WriteSteamId(outMsg, remotePeer.OwnerSteamId.Fallback(steamUserId));
outMsg.Write(data, 1, dataLength - 1);
DeliveryMethod deliveryMethod = (DeliveryMethod)data[0];
PacketHeader packetHeader = (PacketHeader)data[1];
if (!remotePeer.Authenticated & !remotePeer.Authenticating && packetHeader.IsConnectionInitializationStep())
if (!remotePeer.Authenticated && !remotePeer.Authenticating && packetHeader.IsConnectionInitializationStep())
{
remotePeer.DisconnectTime = null;
@@ -240,7 +239,7 @@ namespace Barotrauma.Networking
{
if (!isActive) { return; }
UInt64 recipientSteamId = ReadSteamId(inc);
SteamId recipientSteamId = ReadSteamId(inc);
DeliveryMethod deliveryMethod = (DeliveryMethod)inc.ReadByte();
int p2pDataStart = inc.BytePosition;
@@ -255,7 +254,7 @@ namespace Barotrauma.Networking
return;
}
RemotePeer peer = remotePeers.Find(p => p.SteamID == recipientSteamId);
RemotePeer peer = remotePeers.Find(p => p.SteamId == recipientSteamId);
if (peer == null) { return; }
@@ -314,7 +313,7 @@ namespace Barotrauma.Networking
sendType = Steamworks.P2PSend.Reliable;
}
bool successSend = Steamworks.SteamNetworking.SendP2PPacket(recipientSteamId, p2pData, p2pData.Length, 0, sendType);
bool successSend = Steamworks.SteamNetworking.SendP2PPacket(recipientSteamId.Value, p2pData, p2pData.Length, 0, sendType);
sentBytes += p2pData.Length;
if (!successSend)
@@ -323,7 +322,7 @@ namespace Barotrauma.Networking
{
DebugConsole.Log("WARNING: message couldn't be sent unreliably, forcing reliable send (" + p2pData.Length.ToString() + " bytes)");
sendType = Steamworks.P2PSend.Reliable;
successSend = Steamworks.SteamNetworking.SendP2PPacket(recipientSteamId, p2pData, p2pData.Length, 0, sendType);
successSend = Steamworks.SteamNetworking.SendP2PPacket(recipientSteamId.Value, p2pData, p2pData.Length, 0, sendType);
sentBytes += p2pData.Length;
}
if (!successSend)
@@ -354,7 +353,7 @@ namespace Barotrauma.Networking
WriteSteamId(outMsg, selfSteamID);
WriteSteamId(outMsg, selfSteamID);
outMsg.Write((byte)(PacketHeader.IsConnectionInitializationStep));
outMsg.Write(Name);
outMsg.Write(GameMain.Client.Name);
byte[] msgToSend = (byte[])outMsg.Buffer.Clone();
Array.Resize(ref msgToSend, outMsg.LengthBytes);
@@ -365,12 +364,12 @@ namespace Barotrauma.Networking
{
if (initializationStep != ConnectionInitialization.Success)
{
OnInitializationComplete?.Invoke();
callbacks.OnInitializationComplete.Invoke();
initializationStep = ConnectionInitialization.Success;
}
UInt16 length = inc.ReadUInt16();
IReadMessage msg = new ReadOnlyMessage(inc.Buffer, packetHeader.IsCompressed(), inc.BytePosition, length, ServerConnection);
OnMessageReceived?.Invoke(msg);
callbacks.OnMessageReceived.Invoke(msg);
return;
}
@@ -390,7 +389,7 @@ namespace Barotrauma.Networking
outMsg.Write((byte)(PacketHeader.IsServerMessage | PacketHeader.IsDisconnectMessage));
outMsg.Write(msg);
Steamworks.SteamNetworking.SendP2PPacket(peer.SteamID, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
Steamworks.SteamNetworking.SendP2PPacket(peer.SteamId.Value, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
}
else
@@ -401,7 +400,7 @@ namespace Barotrauma.Networking
private void ClosePeerSession(RemotePeer peer)
{
Steamworks.SteamNetworking.CloseP2PSessionWithUser(peer.SteamID);
Steamworks.SteamNetworking.CloseP2PSessionWithUser(peer.SteamId.Value);
remotePeers.Remove(peer);
}
@@ -430,7 +429,7 @@ namespace Barotrauma.Networking
ChildServerRelay.ClosePipes();
OnDisconnect?.Invoke(disableReconnect);
callbacks.OnDisconnect.Invoke(disableReconnect);
SteamManager.LeaveLobby();
Steamworks.SteamNetworking.ResetActions();
@@ -3,7 +3,6 @@ using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Xml.Linq;
@@ -11,13 +10,14 @@ namespace Barotrauma.Networking
{
class ServerInfo
{
public string IP;
public string Port;
public string QueryPort;
public Steamworks.Data.NetPingLocation? PingLocation;
public Endpoint Endpoint;
#region TODO: genericize
public int QueryPort;
public UInt64 LobbyID;
public UInt64 OwnerID;
public Steamworks.Data.NetPingLocation? PingLocation;
#endregion
public bool OwnerVerified;
private string serverName;
@@ -42,7 +42,7 @@ namespace Barotrauma.Networking
//null value means that the value isn't known (the server may be using
//an old version of the game that didn't report these values or the FetchRules query to Steam may not have finished yet)
public bool? UsingWhiteList;
// TODO: death to Nullable<T>!!!!
public SelectionMode? ModeSelectionMode;
public SelectionMode? SubSelectionMode;
public bool? AllowSpectating;
@@ -140,7 +140,7 @@ namespace Barotrauma.Networking
}
var serverType = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), frame.RectTransform),
TextManager.Get((OwnerID != 0 || LobbyID != 0) ? "SteamP2PServer" : "DedicatedServer"),
Endpoint.ServerTypeString,
textAlignment: Alignment.TopLeft)
{
CanBeFocused = false
@@ -248,20 +248,6 @@ namespace Barotrauma.Networking
else
voipEnabledTickBox.Selected = VoipEnabled.Value;*/
var usingWhiteList = new GUITickBox(new RectTransform(new Vector2(1, elementHeight), content.RectTransform), TextManager.Get("ServerListUsingWhitelist"))
{
CanBeFocused = false
};
if (!UsingWhiteList.HasValue)
new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.8f), usingWhiteList.Box.RectTransform, Anchor.Center), "?", textAlignment: Alignment.Center);
else
usingWhiteList.Selected = UsingWhiteList.Value;
content.RectTransform.SizeChanged += () =>
{
GUITextBlock.AutoScaleAndNormalize(allowSpectating.TextBlock, allowRespawn.TextBlock, usingWhiteList.TextBlock);
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform),
TextManager.Get("ServerListContentPackages"), textAlignment: Alignment.Center, font: GUIStyle.SubHeadingFont);
@@ -350,34 +336,27 @@ namespace Barotrauma.Networking
public static ServerInfo FromXElement(XElement element)
{
ServerInfo info = new ServerInfo()
string endpointStr
= element.GetAttributeString("Endpoint", null)
?? element.GetAttributeString("OwnerID", null)
?? $"{element.GetAttributeString("IP", "")}:{element.GetAttributeInt("Port", 0)}";
if (!(Endpoint.Parse(endpointStr).TryUnwrap(out var endpoint))) { return null; }
ServerInfo info = new ServerInfo
{
ServerName = element.GetAttributeString("ServerName", ""),
ServerMessage = element.GetAttributeString("ServerMessage", ""),
IP = element.GetAttributeString("IP", ""),
Port = element.GetAttributeString("Port", ""),
QueryPort = element.GetAttributeString("QueryPort", ""),
OwnerID = element.GetAttributeSteamID("OwnerID",0)
Endpoint = endpoint,
QueryPort = element.GetAttributeInt("QueryPort", 0),
GameMode = element.GetAttributeIdentifier("GameMode", Identifier.Empty),
GameVersion = element.GetAttributeString("GameVersion", ""),
MaxPlayers = Math.Min(element.GetAttributeInt("MaxPlayers", 0), NetConfig.MaxPlayers),
HasPassword = element.GetAttributeBool("HasPassword", false),
RespondedToSteamQuery = null
};
info.RespondedToSteamQuery = null;
info.GameMode = element.GetAttributeIdentifier("GameMode", Identifier.Empty);
info.GameVersion = element.GetAttributeString("GameVersion", "");
int maxPlayersElement = element.GetAttributeInt("MaxPlayers", 0);
if (maxPlayersElement > NetConfig.MaxPlayers)
{
/*DebugConsole.IsOpen = true;
DebugConsole.NewMessage($"Setting the maximum amount of players to {maxPlayersElement} failed due to exceeding the limit of {NetConfig.MaxPlayers} players per server. Using the maximum of {NetConfig.MaxPlayers} instead.", Color.Red);*/
maxPlayersElement = NetConfig.MaxPlayers;
}
info.MaxPlayers = maxPlayersElement;
if (Enum.TryParse(element.GetAttributeString("PlayStyle", ""), out PlayStyle playStyleTemp)) { info.PlayStyle = playStyleTemp; }
if (bool.TryParse(element.GetAttributeString("UsingWhiteList", ""), out bool whitelistTemp)) { info.UsingWhiteList = whitelistTemp; }
if (Enum.TryParse(element.GetAttributeString("TraitorsEnabled", ""), out YesNoMaybe traitorsTemp)) { info.TraitorsEnabled = traitorsTemp; }
if (Enum.TryParse(element.GetAttributeString("SubSelectionMode", ""), out SelectionMode subSelectionTemp)) { info.SubSelectionMode = subSelectionTemp; }
if (Enum.TryParse(element.GetAttributeString("ModeSelectionMode", ""), out SelectionMode modeSelectionTemp)) { info.ModeSelectionMode = modeSelectionTemp; }
@@ -385,8 +364,6 @@ namespace Barotrauma.Networking
if (bool.TryParse(element.GetAttributeString("KarmaEnabled", ""), out bool karmaTemp)) { info.KarmaEnabled = karmaTemp; }
if (bool.TryParse(element.GetAttributeString("FriendlyFireEnabled", ""), out bool friendlyFireTemp)) { info.FriendlyFireEnabled = friendlyFireTemp; }
info.HasPassword = element.GetAttributeBool("HasPassword", false);
return info;
}
@@ -394,9 +371,9 @@ namespace Barotrauma.Networking
{
if (!SteamManager.IsInitialized) { return; }
if (int.TryParse(QueryPort, out int parsedPort) && IPAddress.TryParse(IP, out IPAddress parsedIP))
if (QueryPort != 0 && Endpoint is LidgrenEndpoint { NetEndpoint: { Address: var ipAddress } })
{
if (MatchmakingPingResponse?.QueryActive ?? false)
if (MatchmakingPingResponse is { QueryActive: true })
{
MatchmakingPingResponse.Cancel();
}
@@ -433,14 +410,11 @@ namespace Barotrauma.Networking
RespondedToSteamQuery = false;
});
MatchmakingPingResponse.HQueryPing(parsedIP, parsedPort);
MatchmakingPingResponse.HQueryPing(ipAddress, QueryPort);
}
else if (OwnerID != 0)
else if (Endpoint is SteamP2PEndpoint { SteamId: var ownerId })
{
if (SteamFriend == null)
{
SteamFriend = new Steamworks.Friend(OwnerID);
}
SteamFriend ??= new Steamworks.Friend(ownerId.Value);
if (LobbyID == 0)
{
TaskPool.Add("RequestSteamP2POwnerInfo", SteamFriend?.RequestInfoAsync(),
@@ -474,20 +448,15 @@ namespace Barotrauma.Networking
bool.TryParse(lobby.GetData("haspassword"), out bool hasPassword);
int.TryParse(lobby.GetData("playercount"), out int currPlayers);
int.TryParse(lobby.GetData("maxplayernum"), out int maxPlayers);
UInt64 ownerId = SteamManager.SteamIDStringToUInt64(lobby.GetData("lobbyowner"));
if (OwnerID != ownerId) { return; }
if (!SteamId.Parse(lobby.GetData("lobbyowner")).TryUnwrap(out var ownerId)) { return; }
if (!(Endpoint is SteamP2PEndpoint { SteamId: var id }) || id != ownerId) { return; }
ServerName = lobby.GetData("name");
IP = "";
Port = "";
QueryPort = "";
PlayerCount = currPlayers;
MaxPlayers = maxPlayers;
HasPassword = hasPassword;
RespondedToSteamQuery = true;
LobbyID = lobby.Id;
OwnerID = ownerId;
PingChecked = false;
OwnerVerified = true;
@@ -496,7 +465,7 @@ namespace Barotrauma.Networking
public XElement ToXElement()
{
if (OwnerID == 0 && string.IsNullOrEmpty(Port))
if (Endpoint is null)
{
return null; //can't save this one since it's not set up correctly
}
@@ -505,22 +474,12 @@ namespace Barotrauma.Networking
element.SetAttributeValue("ServerName", ServerName);
element.SetAttributeValue("ServerMessage", ServerMessage);
if (OwnerID == 0)
{
element.SetAttributeValue("IP", IP);
element.SetAttributeValue("Port", Port);
element.SetAttributeValue("QueryPort", QueryPort);
}
else
{
element.SetAttributeValue("OwnerID", SteamManager.SteamIDUInt64ToString(OwnerID));
}
element.SetAttributeValue("Endpoint", Endpoint.ToString());
element.SetAttributeValue("GameMode", GameMode);
element.SetAttributeValue("GameVersion", GameVersion ?? "");
element.SetAttributeValue("MaxPlayers", MaxPlayers);
if (PlayStyle.HasValue) { element.SetAttributeValue("PlayStyle", PlayStyle.Value.ToString()); }
if (UsingWhiteList.HasValue) { element.SetAttributeValue("UsingWhiteList", UsingWhiteList.Value.ToString()); }
if (TraitorsEnabled.HasValue) { element.SetAttributeValue("TraitorsEnabled", TraitorsEnabled.Value.ToString()); }
if (SubSelectionMode.HasValue) { element.SetAttributeValue("SubSelectionMode", SubSelectionMode.Value.ToString()); }
if (ModeSelectionMode.HasValue) { element.SetAttributeValue("ModeSelectionMode", ModeSelectionMode.Value.ToString()); }
@@ -540,14 +499,19 @@ namespace Barotrauma.Networking
public bool Equals(ServerInfo other)
{
return
other.OwnerID == OwnerID &&
(other.LobbyID == LobbyID || other.LobbyID == 0 || LobbyID == 0) &&
((OwnerID == 0) ? (other.IP == IP && other.Port == Port) : true);
other.Endpoint == Endpoint &&
(other.LobbyID == LobbyID || other.LobbyID == 0 || LobbyID == 0);
}
/// <summary>
/// This class is trash, so punish its use by making it horribly inefficient in hashsets
/// Doing anything else here would make it cause even more bugs
/// </summary>
public override int GetHashCode() => 0;
public bool MatchesByEndpoint(ServerInfo other)
{
return OwnerID == other.OwnerID && (OwnerID != 0 ? true : (IP == other.IP && Port == other.Port));
return other.Endpoint == Endpoint;
}
}
}
@@ -1,9 +1,9 @@
using Microsoft.Xna.Framework;
using Barotrauma.Extensions;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework.Graphics;
using Barotrauma.Extensions;
namespace Barotrauma.Networking
{
@@ -196,11 +196,7 @@ namespace Barotrauma.Networking
{
foreach (var data in richString.RichTextData.Value)
{
if (!UInt64.TryParse(data.Metadata, out ulong id)) { return; }
Client client = GameMain.Client.ConnectedClients.Find(c => c.SteamID == id)
?? GameMain.Client.ConnectedClients.Find(c => c.ID == id)
?? GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.SteamID == id)
?? GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.ID == id);
Client client = data.ExtractClient();
if (client != null && client.Karma < 40.0f)
{
textContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.0f), listBox.Content.RectTransform),
@@ -258,11 +254,8 @@ namespace Barotrauma.Networking
foreach (GUIComponent child in listBox.Content.Children)
{
var textBlock = child as GUITextBlock;
if (textBlock == null) continue;
if (!(child is GUITextBlock textBlock)) { continue; }
child.Visible = true;
if (msgTypeHidden[(int)((LogMessage)child.UserData).Type])
{
child.Visible = false;
@@ -287,10 +280,10 @@ namespace Barotrauma.Networking
listBox.Content.RectTransform.ReverseChildren();
}
public bool ClearFilter(GUIComponent button, object obj)
public bool ClearFilter(GUIComponent button, object _)
{
var searchBox = button.UserData as GUITextBox;
if (searchBox != null) searchBox.Text = "";
if (searchBox != null) { searchBox.Text = ""; }
msgFilter = "";
FilterMessages();
@@ -121,7 +121,6 @@ namespace Barotrauma.Networking
ReadMonsterEnabled(incMsg);
BanList.ClientAdminRead(incMsg);
Whitelist.ClientAdminRead(incMsg);
}
public void ClientRead(IReadMessage incMsg)
@@ -225,7 +224,6 @@ namespace Barotrauma.Networking
outMsg.Write(changedMonsterSettings); outMsg.WritePadBits();
if (changedMonsterSettings) WriteMonsterEnabled(outMsg, tempMonsterEnabled);
BanList.ClientAdminWrite(outMsg);
Whitelist.ClientAdminWrite(outMsg);
}
if (dataToSend.HasFlag(NetFlags.HiddenSubs))
@@ -273,8 +271,7 @@ namespace Barotrauma.Networking
General,
Rounds,
Antigriefing,
Banlist,
Whitelist
Banlist
}
private NetPropertyData GetPropertyData(string name)
@@ -949,13 +946,6 @@ namespace Barotrauma.Networking
//--------------------------------------------------------------------------------
BanList.CreateBanFrame(settingsTabs[(int)SettingsTab.Banlist]);
//--------------------------------------------------------------------------------
// whitelist
//--------------------------------------------------------------------------------
Whitelist.CreateWhiteListFrame(settingsTabs[(int)SettingsTab.Whitelist]);
Whitelist.localEnabled = Whitelist.Enabled;
}
private void CreateLabeledSlider(GUIComponent parent, string labelTag, out GUIScrollBar slider, out GUITextBlock label)
@@ -53,7 +53,7 @@ namespace Barotrauma.Networking
{
get
{
return GameMain.Client?.ID ?? 0;
return GameMain.Client?.SessionId ?? 0;
}
protected set
{
@@ -82,7 +82,7 @@ namespace Barotrauma.Networking
}
}
private VoipCapture(string deviceName) : base(GameMain.Client?.ID ?? 0, true, false)
private VoipCapture(string deviceName) : base(GameMain.Client?.SessionId ?? 0, true, false)
{
Disconnected = false;
@@ -2,6 +2,7 @@
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Linq;
using Barotrauma.Extensions;
namespace Barotrauma
{
@@ -54,7 +55,7 @@ namespace Barotrauma
voteCountMax[voteType] = value;
}
public void UpdateVoteTexts(List<Client> clients, VoteType voteType)
public void UpdateVoteTexts(IEnumerable<Client> clients, VoteType voteType)
{
switch (voteType)
{
@@ -92,7 +93,7 @@ namespace Barotrauma
private void SetVoteText(GUIListBox listBox, object userData, int votes)
{
if (userData == null) return;
if (userData == null) { return; }
foreach (GUIComponent comp in listBox.Content.Children)
{
if (comp.UserData != userData) { continue; }
@@ -136,7 +137,7 @@ namespace Barotrauma
case VoteType.Kick:
if (!(data is Client votedClient)) { return; }
msg.Write(votedClient.ID);
msg.Write(votedClient.SessionId);
break;
case VoteType.StartRound:
if (!(data is bool)) { return; }
@@ -233,21 +234,22 @@ namespace Barotrauma
DebugConsole.ThrowError("Failed to cast vote type \"" + voteTypeByte + "\"", e);
}
byte yesClientCount = inc.ReadByte();
for (int i = 0; i < yesClientCount; i++)
int readVote(int value)
{
byte clientID = inc.ReadByte();
var matchingClient = GameMain.NetworkMember.ConnectedClients.Find(c => c.ID == clientID);
matchingClient?.SetVote(voteType, 2);
}
byte clientCount = inc.ReadByte();
for (int i = 0; i < clientCount; i++)
{
byte clientId = inc.ReadByte();
var matchingClient = GameMain.NetworkMember.ConnectedClients.Find(c => c.SessionId == clientId);
matchingClient?.SetVote(voteType, value);
}
byte noClientCount = inc.ReadByte();
for (int i = 0; i < noClientCount; i++)
{
byte clientID = inc.ReadByte();
var matchingClient = GameMain.NetworkMember.ConnectedClients.Find(c => c.ID == clientID);
matchingClient?.SetVote(voteType, 1);
return clientCount;
}
int yesClientCount = readVote(value: 2);
int noClientCount = readVote(value: 1);
byte maxClientCount = inc.ReadByte();
SetVoteCountYes(voteType, yesClientCount);
@@ -258,10 +260,10 @@ namespace Barotrauma
{
case VoteState.Started:
byte starterID = inc.ReadByte();
Client starterClient = GameMain.NetworkMember.ConnectedClients.Find(c => c.ID == starterID);
Client starterClient = GameMain.NetworkMember.ConnectedClients.Find(c => c.SessionId == starterID);
float timeOut = inc.ReadByte();
Client myClient = GameMain.NetworkMember.ConnectedClients.Find(c => c.ID == GameMain.Client.ID);
Client myClient = GameMain.NetworkMember.ConnectedClients.Find(c => c.SessionId == GameMain.Client.SessionId);
if (myClient == null || !myClient.InGame) { return; }
switch (voteType)
@@ -284,8 +286,8 @@ namespace Barotrauma
byte toClientId = inc.ReadByte();
int transferAmount = inc.ReadInt32();
Client fromClient = GameMain.NetworkMember.ConnectedClients.Find(c => c.ID == fromClientId);
Client toClient = GameMain.NetworkMember.ConnectedClients.Find(c => c.ID == toClientId);
Client fromClient = GameMain.NetworkMember.ConnectedClients.Find(c => c.SessionId == fromClientId);
Client toClient = GameMain.NetworkMember.ConnectedClients.Find(c => c.SessionId == toClientId);
GameMain.Client.ShowMoneyTransferVoteInterface(starterClient, fromClient, transferAmount, toClient, timeOut);
break;
}
@@ -343,8 +345,8 @@ namespace Barotrauma
byte readyClientCount = inc.ReadByte();
for (int i = 0; i < readyClientCount; i++)
{
byte clientID = inc.ReadByte();
var matchingClient = GameMain.NetworkMember.ConnectedClients.Find(c => c.ID == clientID);
byte clientId = inc.ReadByte();
var matchingClient = GameMain.NetworkMember.ConnectedClients.Find(c => c.SessionId == clientId);
matchingClient?.SetVote(VoteType.StartRound, true);
}
UpdateVoteTexts(GameMain.NetworkMember.ConnectedClients, VoteType.StartRound);