diff --git a/Facepunch.Steamworks.Test/ServerlistTest.cs b/Facepunch.Steamworks.Test/ServerlistTest.cs index a6a45c2..2568564 100644 --- a/Facepunch.Steamworks.Test/ServerlistTest.cs +++ b/Facepunch.Steamworks.Test/ServerlistTest.cs @@ -165,5 +165,65 @@ namespace Steamworks } } } - } + + [TestMethod] + public async Task ServerListIps() + { + var ips = new string[] + { + "31.186.251.76", + "31.186.251.76", + "31.186.251.76", + "31.186.251.76", + "31.186.251.76", + "74.91.119.142", + "74.91.119.142", + "74.91.119.142", + "74.91.119.142", + "74.91.119.142", + "74.91.119.142", + "74.91.119.142", + "74.91.119.142", + "74.91.119.142", + "74.91.119.142", + "74.91.119.142", + "74.91.119.142", + "139.99.144.70", + "139.99.144.70", + "139.99.144.70", + "139.99.144.70", + "139.99.144.70", + "74.91.119.142", + "74.91.119.142", + "74.91.119.142", + "74.91.119.142", + "95.172.92.176", + "95.172.92.176", + "95.172.92.176", + "95.172.92.176", + "95.172.92.176", + "164.132.205.154", + "164.132.205.154", + "164.132.205.154", + "164.132.205.154", + "164.132.205.154", + }; + + using ( var list = new ServerList.IpList( ips ) ) + { + var success = await list.RunQueryAsync(); + + Console.WriteLine( $"success {success}" ); + Console.WriteLine( $"Found {list.Responsive.Count} Responsive Servers" ); + Console.WriteLine( $"Found {list.Unresponsive.Count} Unresponsive Servers" ); + + Assert.AreNotEqual( list.Responsive.Count, 0 ); + + foreach ( var server in list.Responsive ) + { + Console.WriteLine( $"[{server.Address}:{server.ConnectionPort}] - {server.Name}" ); + } + } + } + } } diff --git a/Facepunch.Steamworks/ServerList/Base.cs b/Facepunch.Steamworks/ServerList/Base.cs index 1c883ed..36318ee 100644 --- a/Facepunch.Steamworks/ServerList/Base.cs +++ b/Facepunch.Steamworks/ServerList/Base.cs @@ -66,7 +66,7 @@ namespace Steamworks.ServerList /// Query the server list. Task result will be true when finished /// /// - public async Task RunQueryAsync( float timeoutSeconds = 10 ) + public virtual async Task RunQueryAsync( float timeoutSeconds = 10 ) { var stopwatch = System.Diagnostics.Stopwatch.StartNew(); @@ -92,7 +92,7 @@ namespace Steamworks.ServerList if ( r != Responsive.Count ) { - OnChanges?.Invoke(); + InvokeChanges(); } if ( stopwatch.Elapsed.TotalSeconds > timeoutSeconds ) @@ -100,12 +100,12 @@ namespace Steamworks.ServerList } MovePendingToUnresponsive(); - OnChanges?.Invoke(); + InvokeChanges(); return true; } - public void Cancel() => Internal.CancelQuery( request ); + public virtual void Cancel() => Internal.CancelQuery( request ); // Overrides internal abstract void LaunchQuery(); @@ -115,7 +115,7 @@ namespace Steamworks.ServerList #region Filters internal List filters = new List(); - internal MatchMakingKeyValuePair_t[] GetFilters() => filters.ToArray(); + internal virtual MatchMakingKeyValuePair_t[] GetFilters() => filters.ToArray(); public void AddFilter( string key, string value ) { @@ -151,6 +151,11 @@ namespace Steamworks.ServerList ReleaseQuery(); } + internal void InvokeChanges() + { + OnChanges?.Invoke(); + } + void UpdatePending() { var count = Count; diff --git a/Facepunch.Steamworks/ServerList/IpList.cs b/Facepunch.Steamworks/ServerList/IpList.cs new file mode 100644 index 0000000..c76e88c --- /dev/null +++ b/Facepunch.Steamworks/ServerList/IpList.cs @@ -0,0 +1,72 @@ +using Steamworks.Data; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Steamworks.ServerList +{ + public class IpList : Internet + { + public List Ips = new List(); + bool wantsCancel; + + public IpList( IEnumerable list ) + { + Ips.AddRange( list ); + } + + public IpList( params string[] list ) + { + Ips.AddRange( list ); + } + + public override async Task RunQueryAsync( float timeoutSeconds = 10 ) + { + int blockSize = 16; + int pointer = 0; + + var ips = Ips.ToArray(); + + while ( true ) + { + var sublist = ips.Skip( pointer ).Take( blockSize ); + if ( sublist.Count() == 0 ) + break; + + using ( var list = new ServerList.Internet() ) + { + list.AddFilter( "or", sublist.Count().ToString() ); + + foreach ( var server in sublist ) + { + list.AddFilter( "gameaddr", server ); + } + + await list.RunQueryAsync( timeoutSeconds ); + + if ( wantsCancel ) + return false; + + Responsive.AddRange( list.Responsive ); + Responsive = Responsive.Distinct().ToList(); + Unresponsive.AddRange( list.Unresponsive ); + Unresponsive = Unresponsive.Distinct().ToList(); + } + + pointer += sublist.Count(); + + InvokeChanges(); + } + + return true; + } + + public override void Cancel() + { + wantsCancel = true; + } + } +} \ No newline at end of file diff --git a/Facepunch.Steamworks/Structs/Server.cs b/Facepunch.Steamworks/Structs/Server.cs index 0c470d5..df5c620 100644 --- a/Facepunch.Steamworks/Structs/Server.cs +++ b/Facepunch.Steamworks/Structs/Server.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace Steamworks.Data { - public struct ServerInfo + public struct ServerInfo : IEquatable { public string Name { get; set; } public int Ping { get; set; } @@ -118,5 +118,15 @@ namespace Steamworks.Data { //Client.native.matchmaking.RemoveFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagFavorite ); } + + public bool Equals( ServerInfo other ) + { + return this.GetHashCode() == other.GetHashCode(); + } + + public override int GetHashCode() + { + return Address.GetHashCode() + SteamId.GetHashCode() + ConnectionPort.GetHashCode() + QueryPort.GetHashCode(); + } } } \ No newline at end of file