v1.3.0.1 (Epic Store release)
This commit is contained in:
-11
@@ -1,11 +0,0 @@
|
||||
#nullable enable
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
abstract class FriendProvider
|
||||
{
|
||||
public abstract ServerListScreen.FriendInfo[] RetrieveFriends();
|
||||
public abstract void RetrieveAvatar(ServerListScreen.FriendInfo friend, ServerListScreen.AvatarSize avatarSize);
|
||||
public abstract string GetUserName();
|
||||
}
|
||||
}
|
||||
-67
@@ -1,67 +0,0 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Steam;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class SteamFriendProvider : FriendProvider
|
||||
{
|
||||
private static ServerListScreen.FriendInfo FromSteamFriend(Steamworks.Friend steamFriend)
|
||||
=> new ServerListScreen.FriendInfo(
|
||||
steamFriend.Name,
|
||||
new SteamId(steamFriend.Id),
|
||||
steamFriend.State switch
|
||||
{
|
||||
Steamworks.FriendState.Offline => ServerListScreen.FriendInfo.Status.Offline,
|
||||
Steamworks.FriendState.Invisible => ServerListScreen.FriendInfo.Status.Offline,
|
||||
_ when steamFriend.IsPlayingThisGame => ServerListScreen.FriendInfo.Status.PlayingBarotrauma,
|
||||
_ when steamFriend.GameInfo is { GameID: var gameId } && gameId > 0 => ServerListScreen.FriendInfo.Status.PlayingAnotherGame,
|
||||
_ => ServerListScreen.FriendInfo.Status.NotPlaying
|
||||
})
|
||||
{
|
||||
ServerName = steamFriend.GetRichPresence("servername"),
|
||||
ConnectCommand = steamFriend.GetRichPresence("connect") is { } connectCmd
|
||||
? ToolBox.ParseConnectCommand(ToolBox.SplitCommand(connectCmd))
|
||||
: Option<ConnectCommand>.None()
|
||||
};
|
||||
|
||||
public override ServerListScreen.FriendInfo[] RetrieveFriends()
|
||||
=> SteamManager.IsInitialized
|
||||
? Steamworks.SteamFriends.GetFriends().Select(FromSteamFriend).ToArray()
|
||||
: Array.Empty<ServerListScreen.FriendInfo>();
|
||||
|
||||
public override void RetrieveAvatar(ServerListScreen.FriendInfo friend, ServerListScreen.AvatarSize avatarSize)
|
||||
{
|
||||
if (!(friend.Id is SteamId steamId)) { return; }
|
||||
|
||||
Func<Steamworks.SteamId, Task<Steamworks.Data.Image?>> avatarFunc = avatarSize switch
|
||||
{
|
||||
ServerListScreen.AvatarSize.Small => Steamworks.SteamFriends.GetSmallAvatarAsync,
|
||||
ServerListScreen.AvatarSize.Medium => Steamworks.SteamFriends.GetMediumAvatarAsync,
|
||||
ServerListScreen.AvatarSize.Large => Steamworks.SteamFriends.GetLargeAvatarAsync,
|
||||
};
|
||||
TaskPool.Add($"Get{avatarSize}AvatarAsync", avatarFunc(steamId.Value), task =>
|
||||
{
|
||||
if (!task.TryGetResult(out Steamworks.Data.Image? img)) { return; }
|
||||
if (!(img is { } avatarImage)) { return; }
|
||||
|
||||
if (friend.Avatar.TryUnwrap(out var prevAvatar))
|
||||
{
|
||||
prevAvatar.Remove();
|
||||
}
|
||||
|
||||
#warning TODO: create an avatar atlas?
|
||||
var avatarTexture = new Texture2D(GameMain.Instance.GraphicsDevice, (int)avatarImage.Width, (int)avatarImage.Height);
|
||||
avatarTexture.SetData(avatarImage.Data);
|
||||
friend.Avatar = Option<Sprite>.Some(new Sprite(avatarTexture, null, null));
|
||||
});
|
||||
}
|
||||
|
||||
public override string GetUserName()
|
||||
=> SteamManager.GetUsername();
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using Barotrauma.Extensions;
|
||||
using Steamworks.Data;
|
||||
using Color = Microsoft.Xna.Framework.Color;
|
||||
using Socket = System.Net.Sockets.Socket;
|
||||
@@ -34,19 +35,21 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (CoroutineManager.IsCoroutineRunning("ConnectToServer")) { return; }
|
||||
|
||||
switch (serverInfo.Endpoint)
|
||||
var endpointOption = serverInfo.Endpoints.FirstOrNone(e => e is not EosP2PEndpoint);
|
||||
if (!endpointOption.TryUnwrap(out var endpoint)) { return; }
|
||||
|
||||
switch (endpoint)
|
||||
{
|
||||
case LidgrenEndpoint { NetEndpoint: var endPoint }:
|
||||
|
||||
GetIPAddressPing(serverInfo, endPoint, onPingDiscovered);
|
||||
break;
|
||||
case SteamP2PEndpoint steamP2PEndpoint:
|
||||
TaskPool.Add($"EstimateSteamLobbyPing ({steamP2PEndpoint.StringRepresentation})",
|
||||
case SteamP2PEndpoint:
|
||||
TaskPool.Add($"EstimateSteamLobbyPing ({endpoint.StringRepresentation})",
|
||||
EstimateSteamLobbyPing(serverInfo),
|
||||
t =>
|
||||
{
|
||||
if (!t.TryGetResult(out Option<int> ping)) { return; }
|
||||
serverInfo.Ping = ping;
|
||||
if (!t.TryGetResult(out Result<int, SteamLobbyPingError> ping)) { return; }
|
||||
serverInfo.Ping = ping.TryUnwrapSuccess(out var ms) ? Option.Some(ms) : Option.None;
|
||||
onPingDiscovered(serverInfo);
|
||||
});
|
||||
break;
|
||||
@@ -99,35 +102,57 @@ namespace Barotrauma.Networking
|
||||
|
||||
return loadedLobby;
|
||||
}
|
||||
|
||||
private static async Task<Option<int>> EstimateSteamLobbyPing(ServerInfo serverInfo)
|
||||
{
|
||||
if (!(serverInfo.Endpoint is SteamP2PEndpoint { SteamId: var ownerId })) { return Option<int>.None(); }
|
||||
while (!steamPingInfoReady) { await Task.Delay(50); }
|
||||
|
||||
Lobby lobby;
|
||||
private enum SteamLobbyPingError
|
||||
{
|
||||
SteamPingUnsupported,
|
||||
FailedToGetHostLocationData,
|
||||
FailedToParseHostLocationData,
|
||||
PingEstimationFailed
|
||||
}
|
||||
|
||||
private static async Task<Result<int, SteamLobbyPingError>> EstimateSteamLobbyPing(ServerInfo serverInfo)
|
||||
{
|
||||
while (!steamPingInfoReady)
|
||||
{
|
||||
if (!SteamManager.IsInitialized) { return Result.Failure(SteamLobbyPingError.SteamPingUnsupported); }
|
||||
await Task.Delay(50);
|
||||
}
|
||||
|
||||
string pingLocationStr = "";
|
||||
|
||||
if (serverInfo.MetadataSource.TryUnwrap(out SteamP2PServerProvider.DataSource src))
|
||||
{
|
||||
lobby = src.Lobby;
|
||||
var lobby = src.Lobby;
|
||||
pingLocationStr = lobby.GetData("steampinglocation");
|
||||
if (pingLocationStr.IsNullOrEmpty()) { pingLocationStr = lobby.GetData("pinglocation"); }
|
||||
}
|
||||
else
|
||||
else if (serverInfo.MetadataSource.TryUnwrap(out EosServerProvider.DataSource srcEos))
|
||||
{
|
||||
var friendLobby = await GetSteamLobbyForUser(ownerId);
|
||||
if (friendLobby is null) { return Option<int>.None(); }
|
||||
lobby = friendLobby.Value;
|
||||
pingLocationStr = srcEos.SteamPingLocation;
|
||||
}
|
||||
else if (serverInfo.Endpoints.OfType<SteamP2PEndpoint>().FirstOrNone().TryUnwrap(out var steamP2PEndpoint))
|
||||
{
|
||||
var friendLobby = await GetSteamLobbyForUser(steamP2PEndpoint.SteamId);
|
||||
pingLocationStr = friendLobby?.GetData("steampinglocation") ?? "";
|
||||
}
|
||||
|
||||
var pingLocation = NetPingLocation.TryParseFromString(lobby.GetData("pinglocation"));
|
||||
|
||||
if (pingLocationStr.IsNullOrEmpty())
|
||||
{
|
||||
return Result.Failure(SteamLobbyPingError.FailedToGetHostLocationData);
|
||||
}
|
||||
|
||||
var pingLocation = NetPingLocation.TryParseFromString(pingLocationStr);
|
||||
|
||||
if (pingLocation.HasValue && Steamworks.SteamNetworkingUtils.LocalPingLocation.HasValue)
|
||||
{
|
||||
int ping = Steamworks.SteamNetworkingUtils.LocalPingLocation.Value.EstimatePingTo(pingLocation.Value);
|
||||
return ping >= 0 ? Option<int>.Some(ping) : Option<int>.None();
|
||||
if (ping < 0) { return Result.Failure(SteamLobbyPingError.PingEstimationFailed); }
|
||||
return Result.Success(ping);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Option<int>.None();
|
||||
return Result.Failure(SteamLobbyPingError.FailedToParseHostLocationData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,7 +198,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
if (endPoint?.Address == null) { return Option<int>.None(); }
|
||||
|
||||
|
||||
//don't attempt to ping if the address is IPv6 and it's not supported
|
||||
if (endPoint.Address.AddressFamily == AddressFamily.InterNetworkV6 && !Socket.OSSupportsIPv6) { return Option<int>.None(); }
|
||||
|
||||
|
||||
@@ -22,9 +22,9 @@ namespace Barotrauma.Networking
|
||||
public abstract void Write(XElement element);
|
||||
}
|
||||
|
||||
public Endpoint Endpoint { get; private set; }
|
||||
public ImmutableArray<Endpoint> Endpoints { get; }
|
||||
|
||||
public Option<DataSource> MetadataSource = Option<DataSource>.None();
|
||||
public Option<DataSource> MetadataSource = Option.None;
|
||||
|
||||
[Serialize("", IsPropertySaveable.Yes)]
|
||||
public string ServerName { get; set; } = "";
|
||||
@@ -75,6 +75,8 @@ namespace Barotrauma.Networking
|
||||
[Serialize("", IsPropertySaveable.Yes)]
|
||||
public LanguageIdentifier Language { get; set; }
|
||||
|
||||
public bool EosCrossplay { get; set; }
|
||||
|
||||
[Serialize("", IsPropertySaveable.Yes)]
|
||||
public string SelectedSub { get; set; } = string.Empty;
|
||||
|
||||
@@ -84,49 +86,30 @@ namespace Barotrauma.Networking
|
||||
|
||||
public bool Checked = false;
|
||||
|
||||
public readonly struct ContentPackageInfo
|
||||
{
|
||||
public readonly string Name;
|
||||
public readonly string Hash;
|
||||
public readonly Option<ContentPackageId> Id;
|
||||
|
||||
public ContentPackageInfo(string name, string hash, Option<ContentPackageId> id)
|
||||
{
|
||||
Name = name;
|
||||
Hash = hash;
|
||||
Id = id;
|
||||
}
|
||||
|
||||
public ContentPackageInfo(ContentPackage pkg)
|
||||
{
|
||||
Name = pkg.Name;
|
||||
Hash = pkg.Hash.StringRepresentation;
|
||||
Id = pkg.UgcId;
|
||||
}
|
||||
}
|
||||
|
||||
public ImmutableArray<ContentPackageInfo> ContentPackages;
|
||||
public ImmutableArray<ServerListContentPackageInfo> ContentPackages;
|
||||
|
||||
public int ContentPackageCount;
|
||||
|
||||
public bool IsModded => ContentPackages.Any(p => !GameMain.VanillaContent.NameMatches(p.Name));
|
||||
|
||||
public ServerInfo(Endpoint endpoint)
|
||||
public ServerInfo(params Endpoint[] endpoint) : this(endpoint.ToImmutableArray()) { }
|
||||
|
||||
public ServerInfo(ImmutableArray<Endpoint> endpoints)
|
||||
{
|
||||
SerializableProperties = SerializableProperty.GetProperties(this);
|
||||
Endpoint = endpoint;
|
||||
ContentPackages = ImmutableArray<ContentPackageInfo>.Empty;
|
||||
Endpoints = endpoints;
|
||||
ContentPackages = ImmutableArray<ServerListContentPackageInfo>.Empty;
|
||||
}
|
||||
|
||||
public static ServerInfo FromServerConnection(NetworkConnection connection, ServerSettings serverSettings)
|
||||
public static ServerInfo FromServerEndpoints(ImmutableArray<Endpoint> endpoints, ServerSettings serverSettings)
|
||||
{
|
||||
var serverInfo = new ServerInfo(connection.Endpoint)
|
||||
var serverInfo = new ServerInfo(endpoints)
|
||||
{
|
||||
GameMode = GameMain.NetLobbyScreen.SelectedMode?.Identifier ?? Identifier.Empty,
|
||||
GameStarted = Screen.Selected != GameMain.NetLobbyScreen,
|
||||
GameVersion = GameMain.Version,
|
||||
PlayerCount = GameMain.Client.ConnectedClients.Count,
|
||||
ContentPackages = ContentPackageManager.EnabledPackages.All.Select(p => new ContentPackageInfo(p)).ToImmutableArray(),
|
||||
ContentPackages = ContentPackageManager.EnabledPackages.All.Select(p => new ServerListContentPackageInfo(p)).ToImmutableArray(),
|
||||
Ping = GameMain.Client.Ping,
|
||||
|
||||
// -------------------------------------
|
||||
@@ -225,7 +208,7 @@ namespace Barotrauma.Networking
|
||||
playStyleName.RectTransform.IsFixedSize = true;
|
||||
|
||||
var serverType = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), frame.RectTransform),
|
||||
Endpoint?.ServerTypeString ?? string.Empty,
|
||||
Endpoints.First().ServerTypeString,
|
||||
textAlignment: Alignment.TopLeft)
|
||||
{
|
||||
CanBeFocused = false
|
||||
@@ -460,8 +443,12 @@ namespace Barotrauma.Networking
|
||||
GameVersion = version;
|
||||
}
|
||||
if (int.TryParse(valueGetter("playercount"), out int playerCount)) { PlayerCount = playerCount; }
|
||||
if (int.TryParse(valueGetter("maxplayernum"), out int maxPlayers)) { MaxPlayers = maxPlayers; }
|
||||
|
||||
if (int.TryParse(valueGetter("maxplayers"), out int maxPlayers)) { MaxPlayers = maxPlayers; }
|
||||
else if (int.TryParse(valueGetter("maxplayernum"), out maxPlayers)) { MaxPlayers = maxPlayers; }
|
||||
|
||||
if (Enum.TryParse(valueGetter("modeselectionmode"), out SelectionMode modeSelectionMode)) { ModeSelectionMode = modeSelectionMode; }
|
||||
|
||||
if (Enum.TryParse(valueGetter("subselectionmode"), out SelectionMode subSelectionMode)) { SubSelectionMode = subSelectionMode; }
|
||||
|
||||
HasPassword = getBool("haspassword");
|
||||
@@ -471,6 +458,8 @@ namespace Barotrauma.Networking
|
||||
AllowSpectating = getBool("allowspectating");
|
||||
AllowRespawn = getBool("allowrespawn");
|
||||
VoipEnabled = getBool("voicechatenabled");
|
||||
EosCrossplay = getBool("eoscrossplay");
|
||||
|
||||
GameMode = valueGetter("gamemode")?.ToIdentifier() ?? Identifier.Empty;
|
||||
if (float.TryParse(valueGetter("traitors"), NumberStyles.Any, CultureInfo.InvariantCulture, out float traitorProbability)) { TraitorProbability = traitorProbability; }
|
||||
if (Enum.TryParse(valueGetter("playstyle"), out PlayStyle playStyle)) { PlayStyle = playStyle; }
|
||||
@@ -488,27 +477,21 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
private static ContentPackageInfo[] ExtractContentPackageInfo(string serverName, Func<string, string?> valueGetter)
|
||||
private static ServerListContentPackageInfo[] ExtractContentPackageInfo(string serverName, Func<string, string?> valueGetter)
|
||||
{
|
||||
//workaround to ServerRules queries truncating the values to 255 bytes
|
||||
int individualPackageIndex = 0;
|
||||
string? individualPackage = valueGetter($"contentpackage{individualPackageIndex}");
|
||||
if (!individualPackage.IsNullOrEmpty())
|
||||
{
|
||||
List<ContentPackageInfo> contentPackages = new List<ContentPackageInfo>();
|
||||
List<ServerListContentPackageInfo> contentPackages = new List<ServerListContentPackageInfo>();
|
||||
do
|
||||
{
|
||||
string[] splitPackageInfo = individualPackage.Split(',');
|
||||
if (splitPackageInfo.Length != 3)
|
||||
if (!ServerListContentPackageInfo.ParseSingleEntry(individualPackage).TryUnwrap(out var info))
|
||||
{
|
||||
DebugConsole.Log(
|
||||
$"Error in a server's content package list: malformed content package info ({individualPackage}).");
|
||||
return Array.Empty<ContentPackageInfo>();
|
||||
return Array.Empty<ServerListContentPackageInfo>();
|
||||
}
|
||||
string name = splitPackageInfo[0];
|
||||
string hash = splitPackageInfo[1];
|
||||
ulong.TryParse(splitPackageInfo[2], out ulong id);
|
||||
contentPackages.Add(new ContentPackageInfo(name, hash, Option<ContentPackageId>.Some(new SteamWorkshopId(id))));
|
||||
contentPackages.Add(info);
|
||||
|
||||
individualPackageIndex++;
|
||||
individualPackage = valueGetter($"contentpackage{individualPackageIndex}");
|
||||
@@ -518,43 +501,58 @@ namespace Barotrauma.Networking
|
||||
|
||||
string? joinedNames = valueGetter("contentpackage");
|
||||
string? joinedHashes = valueGetter("contentpackagehash");
|
||||
string? joinedWorkshopIds = valueGetter("contentpackageid");
|
||||
string? joinedUgcIds = valueGetter("contentpackageid");
|
||||
|
||||
string[] contentPackageNames = joinedNames.IsNullOrEmpty() ? Array.Empty<string>() : joinedNames.Split(',');
|
||||
string[] contentPackageHashes = joinedHashes.IsNullOrEmpty() ? Array.Empty<string>() : joinedHashes.Split(',');
|
||||
#warning TODO: genericize
|
||||
ulong[] contentPackageIds = joinedWorkshopIds.IsNullOrEmpty() ? new ulong[1] : SteamManager.ParseWorkshopIds(joinedWorkshopIds).ToArray();
|
||||
var contentPackageNames = joinedNames.IsNullOrEmpty() ? Array.Empty<string>() : joinedNames.SplitEscaped(',');
|
||||
var contentPackageHashes = joinedHashes.IsNullOrEmpty() ? Array.Empty<string>() : joinedHashes.SplitEscaped(',');
|
||||
var contentPackageIds = joinedUgcIds.IsNullOrEmpty() ? new string[1] { string.Empty } : joinedUgcIds.SplitEscaped(',');
|
||||
|
||||
if (contentPackageNames.Length != contentPackageHashes.Length || contentPackageHashes.Length != contentPackageIds.Length)
|
||||
if (contentPackageNames.Count != contentPackageHashes.Count || contentPackageHashes.Count != contentPackageIds.Count)
|
||||
{
|
||||
DebugConsole.Log(
|
||||
$"The number of names, hashes and Workshop IDs on server \"{serverName}\"" +
|
||||
$" doesn't match: {contentPackageNames.Length} names ({string.Join(", ", contentPackageNames)}), {contentPackageHashes.Length} hashes, {contentPackageIds.Length} ids)");
|
||||
return Array.Empty<ContentPackageInfo>();
|
||||
$"The number of names, hashes and UGC IDs on server \"{serverName}\"" +
|
||||
$" doesn't match: {contentPackageNames.Count} names ({string.Join(", ", contentPackageNames)}), {contentPackageHashes.Count} hashes, {contentPackageIds.Count} ids)");
|
||||
return Array.Empty<ServerListContentPackageInfo>();
|
||||
}
|
||||
|
||||
return contentPackageNames
|
||||
.Zip(contentPackageHashes, (name, hash) => (name, hash))
|
||||
.Zip(contentPackageIds, (t1, id) =>
|
||||
new ContentPackageInfo(
|
||||
new ServerListContentPackageInfo(
|
||||
t1.name,
|
||||
t1.hash,
|
||||
Option<ContentPackageId>.Some(new SteamWorkshopId(id))))
|
||||
ContentPackageId.Parse(id)))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public static Option<ServerInfo> FromXElement(XElement element)
|
||||
{
|
||||
var endpoints = new List<Endpoint>();
|
||||
|
||||
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))
|
||||
{
|
||||
endpoints.Add(endpoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
var multipleEndpointStrs
|
||||
= element.GetAttributeStringArray("Endpoints", Array.Empty<string>());
|
||||
endpoints.AddRange(
|
||||
multipleEndpointStrs
|
||||
.Select(Endpoint.Parse)
|
||||
.NotNone());
|
||||
}
|
||||
|
||||
if (!Endpoint.Parse(endpointStr).TryUnwrap(out var endpoint)) { return Option<ServerInfo>.None(); }
|
||||
if (endpoints.Count == 0) { return Option.None; }
|
||||
|
||||
var gameVersionStr = element.GetAttributeString("GameVersion", "");
|
||||
if (!Version.TryParse(gameVersionStr, out var gameVersion)) { gameVersion = GameMain.Version; }
|
||||
var info = new ServerInfo(endpoint)
|
||||
var info = new ServerInfo(endpoints.ToImmutableArray())
|
||||
{
|
||||
GameVersion = gameVersion
|
||||
};
|
||||
@@ -562,14 +560,14 @@ namespace Barotrauma.Networking
|
||||
|
||||
info.MetadataSource = DataSource.Parse(element);
|
||||
|
||||
return Option<ServerInfo>.Some(info);
|
||||
return Option.Some(info);
|
||||
}
|
||||
|
||||
public XElement ToXElement()
|
||||
{
|
||||
XElement element = new XElement(GetType().Name);
|
||||
|
||||
element.SetAttributeValue("Endpoint", Endpoint.ToString());
|
||||
element.SetAttributeValue("Endpoints", string.Join(",", Endpoints.Select(e => e.StringRepresentation)));
|
||||
element.SetAttributeValue("GameVersion", GameVersion.ToString());
|
||||
|
||||
SerializableProperty.SerializeProperties(this, element, saveIfDefault: true);
|
||||
@@ -588,9 +586,9 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
public bool Equals(ServerInfo other)
|
||||
=> other.Endpoint == Endpoint;
|
||||
=> other.Endpoints.Any(e => Endpoints.Contains(e));
|
||||
|
||||
public override int GetHashCode() => Endpoint.GetHashCode();
|
||||
public override int GetHashCode() => Endpoints.First().GetHashCode();
|
||||
|
||||
string ISerializableEntity.Name => "ServerInfo";
|
||||
public Dictionary<Identifier, SerializableProperty> SerializableProperties { get; }
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ namespace Barotrauma
|
||||
this.providers = providers.ToImmutableArray();
|
||||
}
|
||||
|
||||
protected override void RetrieveServersImpl(Action<ServerInfo> onServerDataReceived, Action onQueryCompleted)
|
||||
protected override void RetrieveServersImpl(Action<ServerInfo, ServerProvider> onServerDataReceived, Action onQueryCompleted)
|
||||
{
|
||||
int providersFinished = 0;
|
||||
void ackFinishedProvider()
|
||||
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma;
|
||||
|
||||
sealed class EosServerProvider : ServerProvider
|
||||
{
|
||||
public sealed class DataSource : ServerInfo.DataSource
|
||||
{
|
||||
public readonly string SteamPingLocation;
|
||||
|
||||
public DataSource(string steamPingLocation)
|
||||
{
|
||||
SteamPingLocation = steamPingLocation;
|
||||
}
|
||||
|
||||
public override void Write(XElement element) { /* do nothing */ }
|
||||
}
|
||||
|
||||
protected override void RetrieveServersImpl(Action<ServerInfo, ServerProvider> onServerDataReceived, Action onQueryCompleted)
|
||||
{
|
||||
if (EosInterface.IdQueries.GetLoggedInPuids() is not { Length: > 0 } loggedInPuids) { return; }
|
||||
|
||||
int finishedTaskCount = 0;
|
||||
int totalTaskCount = EosInterface.Sessions.MaxBucketIndex + 1 - EosInterface.Sessions.MinBucketIndex;
|
||||
|
||||
void countTaskFinished()
|
||||
{
|
||||
finishedTaskCount++;
|
||||
if (finishedTaskCount == totalTaskCount)
|
||||
{
|
||||
onQueryCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
void onTaskFinished(Task t)
|
||||
{
|
||||
using var janitor = Janitor.Start();
|
||||
janitor.AddAction(countTaskFinished);
|
||||
|
||||
if (!t.TryGetResult(
|
||||
out Result<ImmutableArray<EosInterface.Sessions.RemoteSession>, EosInterface.Sessions.RemoteSession.Query.Error>? result))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!result.TryUnwrapSuccess(out var sessions))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var addedEndpoints = new HashSet<Endpoint>();
|
||||
foreach (var session in sessions)
|
||||
{
|
||||
if (!session.Attributes.TryGetValue("ServerName".ToIdentifier(), out var serverName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var endpointOption = Endpoint.Parse(session.HostAddress);
|
||||
if (!endpointOption.TryUnwrap(out var primaryEndpoint))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var endpoints = new List<Endpoint> { primaryEndpoint };
|
||||
if (primaryEndpoint is EosP2PEndpoint
|
||||
&& session.Attributes.TryGetValue("SteamP2PEndpoint".ToIdentifier(), out var steamIdStr)
|
||||
&& SteamP2PEndpoint.Parse(steamIdStr).TryUnwrap(out var steamP2PEndpoint))
|
||||
{
|
||||
endpoints.Add(steamP2PEndpoint);
|
||||
}
|
||||
else if (primaryEndpoint is LidgrenEndpoint
|
||||
{
|
||||
Address: LidgrenAddress address, Port: NetConfig.DefaultPort
|
||||
}
|
||||
&& session.Attributes.TryGetValue("Port".ToIdentifier(), out var portStr)
|
||||
&& ushort.TryParse(portStr, out var port))
|
||||
{
|
||||
// Port isn't included as part of the host address
|
||||
// because it's filled in by EOS automatically,
|
||||
// so extract the port from a separate attribute and
|
||||
// fix up the endpoint here
|
||||
primaryEndpoint = new LidgrenEndpoint(address.NetAddress, port);
|
||||
endpoints[0] = primaryEndpoint;
|
||||
}
|
||||
|
||||
// Prevent duplicate entries
|
||||
if (endpoints.Intersect(addedEndpoints).Any())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
addedEndpoints.UnionWith(endpoints);
|
||||
|
||||
var serverInfo = new ServerInfo(endpoints.ToImmutableArray())
|
||||
{
|
||||
ServerName = serverName
|
||||
};
|
||||
serverInfo.UpdateInfo(key =>
|
||||
session.Attributes.TryGetValue(key.ToIdentifier(), out var value) ? value : string.Empty);
|
||||
serverInfo.EosCrossplay = true;
|
||||
serverInfo.Checked = true;
|
||||
|
||||
if (session.Attributes.TryGetValue("steampinglocation".ToIdentifier(), out var steamPingLocation))
|
||||
{
|
||||
serverInfo.MetadataSource = Option.Some((ServerInfo.DataSource)new DataSource(steamPingLocation));
|
||||
}
|
||||
|
||||
onServerDataReceived(serverInfo, this);
|
||||
}
|
||||
};
|
||||
|
||||
for (int bucketIndex = EosInterface.Sessions.MinBucketIndex; bucketIndex <= EosInterface.Sessions.MaxBucketIndex; bucketIndex++)
|
||||
{
|
||||
var query = new EosInterface.Sessions.RemoteSession.Query(
|
||||
BucketIndex: bucketIndex,
|
||||
LocalUserId: loggedInPuids.First(),
|
||||
MaxResults: 200,
|
||||
Attributes: ImmutableDictionary<Identifier, string>.Empty);
|
||||
|
||||
TaskPool.Add(
|
||||
$"{nameof(EosServerProvider)}.{nameof(RetrieveServersImpl)}",
|
||||
query.Run(),
|
||||
onTaskFinished);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Cancel()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -6,12 +6,12 @@ namespace Barotrauma
|
||||
{
|
||||
abstract class ServerProvider
|
||||
{
|
||||
public void RetrieveServers(Action<ServerInfo> onServerDataReceived, Action onQueryCompleted)
|
||||
public void RetrieveServers(Action<ServerInfo, ServerProvider> onServerDataReceived, Action onQueryCompleted)
|
||||
{
|
||||
Cancel();
|
||||
RetrieveServersImpl(onServerDataReceived, onQueryCompleted);
|
||||
}
|
||||
protected abstract void RetrieveServersImpl(Action<ServerInfo> onServerDataReceived, Action onQueryCompleted);
|
||||
protected abstract void RetrieveServersImpl(Action<ServerInfo, ServerProvider> action, Action onQueryCompleted);
|
||||
public abstract void Cancel();
|
||||
}
|
||||
}
|
||||
+10
-9
@@ -46,42 +46,43 @@ namespace Barotrauma
|
||||
MetadataSource = Option<ServerInfo.DataSource>.Some(new DataSource((UInt16)entry.QueryPort))
|
||||
});
|
||||
|
||||
private static void HandleResponsiveServer(Steamworks.Data.ServerInfo entry, Action<ServerInfo> onServerDataReceived)
|
||||
private void HandleResponsiveServer(Steamworks.Data.ServerInfo entry, Action<ServerInfo, ServerProvider> onServerDataReceived)
|
||||
{
|
||||
TaskPool.Add($"QueryServerRules (GetServers, {entry.Name}, {entry.Address})", entry.QueryRulesAsync(),
|
||||
t =>
|
||||
{
|
||||
if (t.Status == TaskStatus.Faulted)
|
||||
{
|
||||
TaskPool.PrintTaskExceptions(t, $"Failed to retrieve rules for {entry.Name}");
|
||||
TaskPool.PrintTaskExceptions(t, $"Failed to retrieve rules for {entry.Name}", msg => DebugConsole.ThrowError(msg));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!t.TryGetResult(out Dictionary<string, string> rules)) { return; }
|
||||
if (!t.TryGetResult(out Dictionary<string, string>? rules)) { return; }
|
||||
if (rules is null) { return; }
|
||||
|
||||
if (!InfoFromListEntry(entry).TryUnwrap(out var serverInfo)) { return; }
|
||||
serverInfo.UpdateInfo(key =>
|
||||
{
|
||||
if (rules.TryGetValue(key, out var val)) { return val; }
|
||||
return null;
|
||||
});
|
||||
serverInfo.Checked = true; //rules != null;
|
||||
serverInfo.Checked = true;
|
||||
|
||||
onServerDataReceived(serverInfo);
|
||||
onServerDataReceived(serverInfo, this);
|
||||
});
|
||||
}
|
||||
|
||||
private static void HandleUnresponsiveServer(Steamworks.Data.ServerInfo entry, Action<ServerInfo> onServerDataReceived)
|
||||
private void HandleUnresponsiveServer(Steamworks.Data.ServerInfo entry, Action<ServerInfo, ServerProvider> onServerDataReceived)
|
||||
{
|
||||
//TODO: do we still want to list unresponsive servers?
|
||||
if (!InfoFromListEntry(entry).TryUnwrap(out var serverInfo)) { return; }
|
||||
onServerDataReceived(serverInfo);
|
||||
onServerDataReceived(serverInfo, this);
|
||||
}
|
||||
|
||||
private Steamworks.ServerList.Internet? serverQuery;
|
||||
private CoroutineHandle? queryCoroutine;
|
||||
|
||||
protected override void RetrieveServersImpl(Action<ServerInfo> onServerDataReceived, Action onQueryCompleted)
|
||||
protected override void RetrieveServersImpl(Action<ServerInfo, ServerProvider> onServerDataReceived, Action onQueryCompleted)
|
||||
{
|
||||
if (!SteamManager.IsInitialized)
|
||||
{
|
||||
@@ -139,7 +140,7 @@ namespace Barotrauma
|
||||
CoroutineManager.StopCoroutines(selfQueryCoroutine);
|
||||
dequeue();
|
||||
|
||||
if (t.Status == TaskStatus.Faulted) { TaskPool.PrintTaskExceptions(t, "Failed to retrieve servers"); }
|
||||
if (t.Status == TaskStatus.Faulted) { TaskPool.PrintTaskExceptions(t, "Failed to retrieve servers", msg => DebugConsole.ThrowError(msg)); }
|
||||
|
||||
selfServerQuery.Dispose();
|
||||
}
|
||||
|
||||
+13
-5
@@ -1,6 +1,7 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Networking;
|
||||
@@ -24,7 +25,7 @@ namespace Barotrauma
|
||||
|
||||
private object? queryRef = null;
|
||||
|
||||
protected override void RetrieveServersImpl(Action<ServerInfo> onServerDataReceived, Action onQueryCompleted)
|
||||
protected override void RetrieveServersImpl(Action<ServerInfo, ServerProvider> onServerDataReceived, Action onQueryCompleted)
|
||||
{
|
||||
if (!SteamManager.IsInitialized)
|
||||
{
|
||||
@@ -61,7 +62,7 @@ namespace Barotrauma
|
||||
// If queryRef != selfQueryRef, this query was cancelled
|
||||
if (!ReferenceEquals(selfQueryRef, queryRef)) { return; }
|
||||
|
||||
if (!t.TryGetResult(out Steamworks.Data.Lobby[] lobbies)
|
||||
if (!t.TryGetResult(out Steamworks.Data.Lobby[]? lobbies)
|
||||
|| lobbies is null
|
||||
|| lobbies.Length == 0)
|
||||
{
|
||||
@@ -74,16 +75,23 @@ namespace Barotrauma
|
||||
string lobbyOwnerStr = lobby.GetData("lobbyowner") ?? "";
|
||||
lobbyQuery = lobbyQuery.WithoutKeyValue("lobbyowner", lobbyOwnerStr);
|
||||
|
||||
string serverName = lobby.GetData("name") ?? "";
|
||||
string serverName = lobby.GetData("servername").FallbackNullOrEmpty(lobby.GetData("name")) ?? "";
|
||||
if (string.IsNullOrEmpty(serverName)) { continue; }
|
||||
|
||||
var ownerId = SteamId.Parse(lobbyOwnerStr);
|
||||
if (!ownerId.TryUnwrap(out var lobbyOwnerId)) { continue; }
|
||||
|
||||
var eosP2PEndpointOption = EosP2PEndpoint
|
||||
.Parse(lobby.GetData("EosEndpoint") ?? "")
|
||||
.Select(e => (Endpoint)e);
|
||||
|
||||
if (retrieved.Contains(lobbyOwnerId)) { continue; }
|
||||
retrieved.Add(lobbyOwnerId);
|
||||
|
||||
var serverInfo = new ServerInfo(new SteamP2PEndpoint(lobbyOwnerId))
|
||||
var endpoints = new List<Endpoint> { new SteamP2PEndpoint(lobbyOwnerId) };
|
||||
if (eosP2PEndpointOption.TryUnwrap(out var eosP2PEndpoint)) { endpoints.Add(eosP2PEndpoint); }
|
||||
|
||||
var serverInfo = new ServerInfo(endpoints.ToImmutableArray())
|
||||
{
|
||||
ServerName = serverName,
|
||||
MetadataSource = Option<ServerInfo.DataSource>.Some(new DataSource(lobby))
|
||||
@@ -91,7 +99,7 @@ namespace Barotrauma
|
||||
serverInfo.UpdateInfo(key => lobby.GetData(key));
|
||||
serverInfo.Checked = true;
|
||||
|
||||
onServerDataReceived(serverInfo);
|
||||
onServerDataReceived(serverInfo, this);
|
||||
}
|
||||
startQuery();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user