3 using System.Collections.Concurrent;
4 using System.Collections.Generic;
5 using System.Threading.Tasks;
25 public new static Option<DataSource>
Parse(XElement element)
26 => element.TryGetAttributeInt(
"QueryPort", out var result)
29 var invalidPort when invalidPort <= 0 || invalidPort > UInt16.MaxValue => Option<DataSource>.None(),
30 var queryPort => Option<DataSource>.Some(
new DataSource((UInt16)queryPort))
32 : Option<DataSource>.None();
34 public override void Write(XElement element) => element.SetAttributeValue(
"QueryPort",
QueryPort);
37 private static Option<ServerInfo> InfoFromListEntry(Steamworks.Data.ServerInfo entry) =>
38 entry.Name.IsNullOrEmpty() || entry.Address is
null
39 ? Option<ServerInfo>.None()
42 ServerName = entry.Name,
43 HasPassword = entry.Passworded,
44 PlayerCount = entry.Players,
45 MaxPlayers = entry.MaxPlayers,
46 MetadataSource = Option<ServerInfo.DataSource>.Some(new DataSource((UInt16)entry.QueryPort))
49 private void HandleResponsiveServer(Steamworks.Data.ServerInfo entry, Action<ServerInfo, ServerProvider> onServerDataReceived)
51 TaskPool.Add($
"QueryServerRules (GetServers, {entry.Name}, {entry.Address})", entry.QueryRulesAsync(),
54 if (t.Status == TaskStatus.Faulted)
56 TaskPool.PrintTaskExceptions(t, $
"Failed to retrieve rules for {entry.Name}", msg => DebugConsole.ThrowError(msg));
60 if (!t.TryGetResult(out Dictionary<string, string>? rules)) { return; }
61 if (rules is
null) {
return; }
63 if (!InfoFromListEntry(entry).TryUnwrap(out var serverInfo)) {
return; }
64 serverInfo.UpdateInfo(key =>
66 if (rules.TryGetValue(key, out var val)) { return val; }
69 serverInfo.Checked =
true;
71 onServerDataReceived(serverInfo,
this);
75 private void HandleUnresponsiveServer(Steamworks.Data.ServerInfo entry, Action<ServerInfo, ServerProvider> onServerDataReceived)
78 if (!InfoFromListEntry(entry).TryUnwrap(out var serverInfo)) {
return; }
79 onServerDataReceived(serverInfo,
this);
82 private Steamworks.ServerList.Internet? serverQuery;
83 private CoroutineHandle? queryCoroutine;
85 protected override void RetrieveServersImpl(Action<ServerInfo, ServerProvider> onServerDataReceived, Action onQueryCompleted)
87 if (!SteamManager.IsInitialized)
95 var selfServerQuery =
new Steamworks.ServerList.Internet();
96 serverQuery = selfServerQuery;
98 ConcurrentQueue<Steamworks.Data.ServerInfo> responsiveServers =
99 new ConcurrentQueue<Steamworks.Data.ServerInfo>();
100 ConcurrentQueue<Steamworks.Data.ServerInfo> unresponsiveServers =
101 new ConcurrentQueue<Steamworks.Data.ServerInfo>();
103 selfServerQuery.OnResponsiveServer = responsiveServers.Enqueue;
104 selfServerQuery.OnUnresponsiveServer = unresponsiveServers.Enqueue;
106 void dequeue(
int? limit =
null)
108 for (
int i = 0; (!limit.HasValue || i < limit) && responsiveServers.TryDequeue(out var serverInfo); i++)
110 HandleResponsiveServer(serverInfo, onServerDataReceived);
113 for (
int i = 0; (!limit.HasValue || i < limit) && unresponsiveServers.TryDequeue(out var serverInfo); i++)
115 HandleUnresponsiveServer(serverInfo, onServerDataReceived);
119 IEnumerable<CoroutineStatus> dequeueCoroutine()
127 var selfQueryCoroutine = CoroutineManager.StartCoroutine(dequeueCoroutine(),
128 $
"{nameof(SteamDedicatedServerProvider)}.{nameof(RetrieveServers)}.{nameof(dequeueCoroutine)}");
129 queryCoroutine = selfQueryCoroutine;
131 TaskPool.Add(
"RunServerQuery", selfServerQuery.RunQueryAsync(timeoutSeconds: 30f),
137 selfServerQuery.OnResponsiveServer = null;
138 selfServerQuery.OnUnresponsiveServer = null;
140 CoroutineManager.StopCoroutines(selfQueryCoroutine);
143 if (t.Status == TaskStatus.Faulted) { TaskPool.PrintTaskExceptions(t,
"Failed to retrieve servers", msg => DebugConsole.ThrowError(msg)); }
145 selfServerQuery.Dispose();
156 if (queryCoroutine !=
null) { CoroutineManager.StopCoroutines(queryCoroutine); }
157 serverQuery?.Dispose();
static new Option< DataSource > Parse(XElement element)
override void Write(XElement element)
readonly UInt16 QueryPort
DataSource(UInt16 queryPort)
override void RetrieveServersImpl(Action< ServerInfo, ServerProvider > onServerDataReceived, Action onQueryCompleted)