diff --git a/Facepunch.Steamworks.Test/Client/Serverlist.cs b/Facepunch.Steamworks.Test/Client/Serverlist.cs index c7dc58f..29614c8 100644 --- a/Facepunch.Steamworks.Test/Client/Serverlist.cs +++ b/Facepunch.Steamworks.Test/Client/Serverlist.cs @@ -134,7 +134,90 @@ namespace Facepunch.Steamworks.Test { using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) { - var query = client.ServerList.History(); + var filter = new Facepunch.Steamworks.ServerList.Filter(); + filter.Add( "appid", client.AppId.ToString() ); + filter.Add( "gamedir", "rust" ); + filter.Add( "secure", "1" ); + + var query = client.ServerList.History( filter ); + + while ( true ) + { + client.Update(); + System.Threading.Thread.Sleep( 2 ); + + if ( query.Finished ) + break; + } + + Console.WriteLine( "Responded: " + query.Responded.Count.ToString() ); + Console.WriteLine( "Unresponsive: " + query.Unresponsive.Count.ToString() ); + + foreach ( var x in query.Responded ) + { + Console.WriteLine( x.Map ); + } + + query.Dispose(); + + for ( int i = 0; i < 100; i++ ) + { + client.Update(); + System.Threading.Thread.Sleep( 1 ); + } + } + } + + [TestMethod] + public void FavouriteList() + { + using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) + { + var filter = new Facepunch.Steamworks.ServerList.Filter(); + filter.Add( "appid", client.AppId.ToString() ); + filter.Add( "gamedir", "rust" ); + filter.Add( "secure", "1" ); + + var query = client.ServerList.Favourites( filter ); + + while ( true ) + { + client.Update(); + System.Threading.Thread.Sleep( 2 ); + + if ( query.Finished ) + break; + } + + Console.WriteLine( "Responded: " + query.Responded.Count.ToString() ); + Console.WriteLine( "Unresponsive: " + query.Unresponsive.Count.ToString() ); + + foreach ( var x in query.Responded ) + { + Console.WriteLine( x.Map ); + } + + query.Dispose(); + + for ( int i = 0; i < 100; i++ ) + { + client.Update(); + System.Threading.Thread.Sleep( 1 ); + } + } + } + + [TestMethod] + public void LocalList() + { + using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) + { + var filter = new Facepunch.Steamworks.ServerList.Filter(); + filter.Add( "appid", client.AppId.ToString() ); + filter.Add( "gamedir", "rust" ); + filter.Add( "secure", "1" ); + + var query = client.ServerList.Local( filter ); while ( true ) { diff --git a/Facepunch.Steamworks/Client.cs b/Facepunch.Steamworks/Client.cs index e7ed62f..4b462a1 100644 --- a/Facepunch.Steamworks/Client.cs +++ b/Facepunch.Steamworks/Client.cs @@ -20,7 +20,8 @@ namespace Facepunch.Steamworks /// public string BetaName { get; private set; } - public Voice Voice { get; internal set; } + public Voice Voice { get; private set; } + public ServerList ServerList { get; private set; } public Client( uint appId ) { @@ -45,6 +46,7 @@ namespace Facepunch.Steamworks // Client only interfaces // Voice = new Voice( this ); + ServerList = new ServerList( this ); Workshop.friends = Friends; @@ -89,6 +91,12 @@ namespace Facepunch.Steamworks Voice = null; } + if ( ServerList != null ) + { + ServerList.Dispose(); + ServerList = null; + } + base.Dispose(); } } diff --git a/Facepunch.Steamworks/Client/ServerList.Request.cs b/Facepunch.Steamworks/Client/ServerList.Request.cs index daefb6a..503ef1f 100644 --- a/Facepunch.Steamworks/Client/ServerList.Request.cs +++ b/Facepunch.Steamworks/Client/ServerList.Request.cs @@ -19,12 +19,19 @@ namespace Facepunch.Steamworks internal IntPtr Request; internal int Pointer = 0; internal List WatchList = new List(); + internal System.Diagnostics.Stopwatch Timer = System.Diagnostics.Stopwatch.StartNew(); internal bool Update( SteamNative.SteamMatchmakingServers servers, Action OnServer, Action OnUpdate ) { if ( Request == IntPtr.Zero ) return true; + if ( Timer.Elapsed.TotalSeconds < 0.5f ) + return false; + + Timer.Reset(); + Timer.Start(); + bool changes = false; // @@ -114,7 +121,7 @@ namespace Facepunch.Steamworks } internal IEnumerable ServerList { get; set; } - + internal Filter Filter { get; set; } internal void StartCustomQuery() { @@ -181,6 +188,9 @@ namespace Facepunch.Steamworks { if ( info.HadSuccessfulResponse ) { + if ( Filter != null && !Filter.Test( info ) ) + return; + Responded.Add( Server.FromSteam( client, info ) ); } else diff --git a/Facepunch.Steamworks/Client/ServerList.Server.cs b/Facepunch.Steamworks/Client/ServerList.Server.cs index 9b2d029..473de8a 100644 --- a/Facepunch.Steamworks/Client/ServerList.Server.cs +++ b/Facepunch.Steamworks/Client/ServerList.Server.cs @@ -29,6 +29,17 @@ namespace Facepunch.Steamworks public int ConnectionPort { get; set; } public int QueryPort { get; set; } + /// + /// Returns true if this server is in the favourites list + /// + public bool Favourite + { + get + { + return Client.ServerList.IsFavourite( this ); + } + } + internal Client Client; public string AddressString @@ -111,6 +122,47 @@ namespace Facepunch.Steamworks if ( OnReceivedRules != null ) OnReceivedRules( Success ); } + + internal const uint k_unFavoriteFlagNone = 0x00; + internal const uint k_unFavoriteFlagFavorite = 0x01; // this game favorite entry is for the favorites list + internal const uint k_unFavoriteFlagHistory = 0x02; // this game favorite entry is for the history list + + /// + /// Add this server to our history list + /// If we're already in the history list, weill set the last played time to now + /// + public void AddToHistory() + { + Client.native.matchmaking.AddFavoriteGame( AppId, Address, (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagHistory, (uint)Utility.Epoch.Current ); + Client.ServerList.UpdateFavouriteList(); + } + + /// + /// Remove this server from our history list + /// + public void RemoveFromHistory() + { + Client.native.matchmaking.RemoveFavoriteGame( AppId, Address, (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagHistory ); + Client.ServerList.UpdateFavouriteList(); + } + + /// + /// Add this server to our favourite list + /// + public void AddToFavourites() + { + Client.native.matchmaking.AddFavoriteGame( AppId, Address, (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagFavorite, (uint)Utility.Epoch.Current ); + Client.ServerList.UpdateFavouriteList(); + } + + /// + /// Remove this server from our favourite list + /// + public void RemoveFromFavourites() + { + Client.native.matchmaking.RemoveFavoriteGame( AppId, Address, (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagFavorite ); + Client.ServerList.UpdateFavouriteList(); + } } } } diff --git a/Facepunch.Steamworks/Client/ServerList.cs b/Facepunch.Steamworks/Client/ServerList.cs index 20538f3..171f5fa 100644 --- a/Facepunch.Steamworks/Client/ServerList.cs +++ b/Facepunch.Steamworks/Client/ServerList.cs @@ -3,27 +3,56 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; +using SteamNative; namespace Facepunch.Steamworks { - public partial class Client : IDisposable + public partial class ServerList : IDisposable { - private ServerList _serverlist; + internal Client client; - public ServerList ServerList + internal ServerList( Client client ) { - get - { - if ( _serverlist == null ) - _serverlist = new ServerList { client = this }; + this.client = client; - return _serverlist; + UpdateFavouriteList(); + } + + HashSet FavouriteHash = new HashSet(); + HashSet HistoryHash = new HashSet(); + + internal void UpdateFavouriteList() + { + FavouriteHash.Clear(); + HistoryHash.Clear(); + + for ( int i=0; i< client.native.matchmaking.GetFavoriteGameCount(); i++ ) + { + AppId_t appid = 0; + uint ip; + ushort conPort; + ushort queryPort; + uint lastplayed; + uint flags; + + client.native.matchmaking.GetFavoriteGame( i, ref appid, out ip, out conPort, out queryPort, out flags, out lastplayed ); + + ulong encoded = ip; + encoded = encoded << 32; + encoded = encoded | (uint)conPort; + + if ( ( flags & Server.k_unFavoriteFlagFavorite ) == Server.k_unFavoriteFlagFavorite ) + FavouriteHash.Add( encoded ); + + if ( ( flags & Server.k_unFavoriteFlagFavorite ) == Server.k_unFavoriteFlagFavorite ) + HistoryHash.Add( encoded ); } } - } - public partial class ServerList - { + public void Dispose() + { + client = null; + } public class Filter : List> { @@ -35,16 +64,19 @@ namespace Facepunch.Steamworks internal IntPtr NativeArray; private IntPtr m_pArrayEntries; + private int AppId = 0; + internal void Start() { var filters = this.Select( x => { + if ( x.Key == "appid" ) AppId = int.Parse( x.Value ); + return new SteamNative.MatchMakingKeyValuePair_t() { Key = x.Key, Value = x.Value }; - } ).ToArray(); int sizeOfMMKVP = Marshal.SizeOf(typeof(SteamNative.MatchMakingKeyValuePair_t)); @@ -71,9 +103,17 @@ namespace Facepunch.Steamworks Marshal.FreeHGlobal( NativeArray ); } } + + internal bool Test( gameserveritem_t info ) + { + if ( AppId != 0 && AppId != info.AppID ) + return false; + + return true; + } } - internal Client client; + [StructLayout( LayoutKind.Sequential )] private struct MatchPair @@ -84,11 +124,14 @@ namespace Facepunch.Steamworks public string value; } + + public Request Internet( Filter filter ) { filter.Start(); var request = new Request( client ); + request.Filter = filter; request.AddRequest( client.native.servers.RequestInternetServerList( client.AppId, filter.NativeArray, (uint) filter.Count, IntPtr.Zero ) ); filter.Free(); @@ -96,6 +139,9 @@ namespace Facepunch.Steamworks return request; } + /// + /// Query a list of addresses. No filters applied. + /// public Request Custom( IEnumerable serverList ) { var request = new Request( client ); @@ -105,52 +151,87 @@ namespace Facepunch.Steamworks } /// - /// History filters don't seem to work, so we don't bother. - /// You should apply them post process'dly + /// Request a list of servers we've been on. History isn't applied automatically + /// You need to call server.AddtoHistoryList() when you join a server etc. /// - public Request History() + public Request History( Filter filter ) { + filter.Start(); + var request = new Request( client ); - request.AddRequest( client.native.servers.RequestHistoryServerList( client.AppId, IntPtr.Zero, 0, IntPtr.Zero ) ); + request.Filter = filter; + request.AddRequest( client.native.servers.RequestHistoryServerList( client.AppId, filter.NativeArray, (uint)filter.Count, IntPtr.Zero ) ); + + filter.Free(); return request; } /// - /// Favourite filters don't seem to work, so we don't bother. - /// You should apply them post process'dly + /// Request a list of servers we've favourited /// - public Request Favourites() + public Request Favourites( Filter filter ) { + filter.Start(); + var request = new Request( client ); - request.AddRequest( client.native.servers.RequestFavoritesServerList( client.AppId, IntPtr.Zero, 0, IntPtr.Zero ) ); + request.Filter = filter; + request.AddRequest( client.native.servers.RequestFavoritesServerList( client.AppId, filter.NativeArray, (uint)filter.Count, IntPtr.Zero ) ); + + filter.Free(); return request; } - public void AddToHistory( Server server ) + /// + /// Request a list of servers that our friends are on + /// + public Request Friends( Filter filter ) { - // client.native.matchmaking + filter.Start(); + + var request = new Request( client ); + request.Filter = filter; + request.AddRequest( client.native.servers.RequestFriendsServerList( client.AppId, filter.NativeArray, (uint)filter.Count, IntPtr.Zero ) ); + + filter.Free(); + + return request; } - public void RemoveFromHistory( Server server ) + /// + /// Request a list of servers that are running on our LAN + /// + public Request Local( Filter filter ) { - // + filter.Start(); + + var request = new Request( client ); + request.Filter = filter; + request.AddRequest( client.native.servers.RequestLANServerList( client.AppId, IntPtr.Zero ) ); + + filter.Free(); + + return request; } - public void AddToFavourite( Server server ) + + internal bool IsFavourite( Server server ) { - // client.native.matchmaking + ulong encoded = server.Address; + encoded = encoded << 32; + encoded = encoded | (uint)server.ConnectionPort; + + return FavouriteHash.Contains( encoded ); } - public void RemoveFromFavourite( Server server ) + internal bool IsHistory( Server server ) { - // - } + ulong encoded = server.Address; + encoded = encoded << 32; + encoded = encoded | (uint)server.ConnectionPort; - public bool IsFavourite( Server server ) - { - return false; + return HistoryHash.Contains( encoded ); } } }