Client LuaCsForBarotrauma
SteamP2PServerProvider.cs
1 #nullable enable
2 using System;
3 using System.Collections.Generic;
4 using System.Collections.Immutable;
5 using System.Threading.Tasks;
6 using System.Xml.Linq;
8 using Barotrauma.Steam;
9 
10 namespace Barotrauma
11 {
13  {
15  {
16  public readonly Steamworks.Data.Lobby Lobby;
17 
18  public override void Write(XElement element) { /* do nothing */ }
19 
20  public DataSource(Steamworks.Data.Lobby lobby)
21  {
22  Lobby = lobby;
23  }
24  }
25 
26  private object? queryRef = null;
27 
28  protected override void RetrieveServersImpl(Action<ServerInfo, ServerProvider> onServerDataReceived, Action onQueryCompleted)
29  {
30  if (!SteamManager.IsInitialized)
31  {
32  onQueryCompleted();
33  return;
34  }
35 
36  // All lambdas and local methods in here must only capture
37  // this call's query, not the provider's latest query
38  var selfQueryRef = new object();
39  queryRef = selfQueryRef;
40 
41  Steamworks.Data.LobbyQuery lobbyQuery = Steamworks.SteamMatchmaking.CreateLobbyQuery()
42  .FilterDistanceWorldwide()
43  .WithMaxResults(50);
44  // Steamworks is unable to retrieve more than 50 lobbies per request
45  // (see https://partner.steamgames.com/doc/features/multiplayer/matchmaking#3)
46  // To work around this, we'll make up to 10 requests, asking to ignore
47  // all previous results in each subsequent request.
48  #warning TODO: do something less horrible here?
49 
50  int requestCount = 0;
51  HashSet<SteamId> retrieved = new HashSet<SteamId>();
52 
53  void startQuery()
54  {
55  if (requestCount >= 10) { return; }
56  requestCount++;
57  TaskPool.Add($"LobbyQuery.RequestAsync ({requestCount})", lobbyQuery.RequestAsync(), onRequestComplete);
58  }
59 
60  void onRequestComplete(Task t)
61  {
62  // If queryRef != selfQueryRef, this query was cancelled
63  if (!ReferenceEquals(selfQueryRef, queryRef)) { return; }
64 
65  if (!t.TryGetResult(out Steamworks.Data.Lobby[]? lobbies)
66  || lobbies is null
67  || lobbies.Length == 0)
68  {
69  onQueryCompleted();
70  return;
71  }
72 
73  foreach (var lobby in lobbies)
74  {
75  string lobbyOwnerStr = lobby.GetData("lobbyowner") ?? "";
76  lobbyQuery = lobbyQuery.WithoutKeyValue("lobbyowner", lobbyOwnerStr);
77 
78  string serverName = lobby.GetData("servername").FallbackNullOrEmpty(lobby.GetData("name")) ?? "";
79  if (string.IsNullOrEmpty(serverName)) { continue; }
80 
81  var ownerId = SteamId.Parse(lobbyOwnerStr);
82  if (!ownerId.TryUnwrap(out var lobbyOwnerId)) { continue; }
83 
84  var eosP2PEndpointOption = EosP2PEndpoint
85  .Parse(lobby.GetData("EosEndpoint") ?? "")
86  .Select(e => (Endpoint)e);
87 
88  if (retrieved.Contains(lobbyOwnerId)) { continue; }
89  retrieved.Add(lobbyOwnerId);
90 
91  var endpoints = new List<Endpoint> { new SteamP2PEndpoint(lobbyOwnerId) };
92  if (eosP2PEndpointOption.TryUnwrap(out var eosP2PEndpoint)) { endpoints.Add(eosP2PEndpoint); }
93 
94  var serverInfo = new ServerInfo(endpoints.ToImmutableArray())
95  {
96  ServerName = serverName,
97  MetadataSource = Option<ServerInfo.DataSource>.Some(new DataSource(lobby))
98  };
99  serverInfo.UpdateInfo(key => lobby.GetData(key));
100  serverInfo.Checked = true;
101 
102  onServerDataReceived(serverInfo, this);
103  }
104  startQuery();
105  }
106 
107  startQuery();
108  }
109 
110  public override void Cancel()
111  {
112  queryRef = null;
113  }
114  }
115 }
override void RetrieveServersImpl(Action< ServerInfo, ServerProvider > onServerDataReceived, Action onQueryCompleted)
static new Option< EosP2PEndpoint > Parse(string endpointStr)