diff --git a/Facepunch.Steamworks.Test/Client.Stats.cs b/Facepunch.Steamworks.Test/Client.Stats.cs deleted file mode 100644 index 20c170c..0000000 --- a/Facepunch.Steamworks.Test/Client.Stats.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Text; -using System.Threading; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Facepunch.Steamworks.Test -{ - public partial class Client - { - [TestMethod] - public void UpdateStats() - { - using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) - { - client.Stats.UpdateStats(); - } - } - - [TestMethod] - public void UpdateSUpdateGlobalStatstats() - { - using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) - { - client.Stats.UpdateGlobalStats( 1 ); - client.Stats.UpdateGlobalStats( 3 ); - client.Stats.UpdateGlobalStats( 7 ); - } - } - } -} diff --git a/Facepunch.Steamworks.Test/Client.cs b/Facepunch.Steamworks.Test/Client.cs index ab34b1c..91fb38b 100644 --- a/Facepunch.Steamworks.Test/Client.cs +++ b/Facepunch.Steamworks.Test/Client.cs @@ -111,26 +111,7 @@ public void GetVoice() } } - [TestMethod] - public void GetServers() - { - using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) - { - var query = client.ServerList.Test(); - for ( int i = 0; i < 100 ; i++ ) - { - client.Update(); - System.Threading.Thread.Sleep( 5 ); - - if ( query.Finished ) - break; - } - - Console.WriteLine( "Responded: " + query.Responded.Count.ToString() ); - Console.WriteLine( "Unresponsive: " + query.Unresponsive.Count.ToString() ); - } - } [TestMethod] public void InventoryDefinitions() diff --git a/Facepunch.Steamworks.Test/Facepunch.Steamworks.Test.csproj b/Facepunch.Steamworks.Test/Facepunch.Steamworks.Test.csproj index 9794db4..4ddfa31 100644 --- a/Facepunch.Steamworks.Test/Facepunch.Steamworks.Test.csproj +++ b/Facepunch.Steamworks.Test/Facepunch.Steamworks.Test.csproj @@ -87,7 +87,7 @@ - + @@ -97,7 +97,8 @@ - + + diff --git a/Facepunch.Steamworks.Test/Client.Networking.cs b/Facepunch.Steamworks.Test/Networking.cs similarity index 89% rename from Facepunch.Steamworks.Test/Client.Networking.cs rename to Facepunch.Steamworks.Test/Networking.cs index 948b0b2..49442e4 100644 --- a/Facepunch.Steamworks.Test/Client.Networking.cs +++ b/Facepunch.Steamworks.Test/Networking.cs @@ -5,7 +5,10 @@ namespace Facepunch.Steamworks.Test { - public partial class Client + [TestClass] + [DeploymentItem( "FacepunchSteamworksApi.dll" )] + [DeploymentItem( "steam_appid.txt" )] + public partial class Networking { [TestMethod] public void PeerToPeerSend() diff --git a/Facepunch.Steamworks.Test/Serverlist.cs b/Facepunch.Steamworks.Test/Serverlist.cs new file mode 100644 index 0000000..af08fa4 --- /dev/null +++ b/Facepunch.Steamworks.Test/Serverlist.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Facepunch.Steamworks.Test +{ + [TestClass] + [DeploymentItem( "FacepunchSteamworksApi.dll" )] + [DeploymentItem( "steam_appid.txt" )] + public partial class ServerList + { + [TestMethod] + public void InternetList() + { + using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) + { + var query = client.ServerList.Test(); + + for ( int i = 0; i < 100; i++ ) + { + client.Update(); + System.Threading.Thread.Sleep( 10 ); + + if ( query.Finished ) + break; + } + + Console.WriteLine( "Responded: " + query.Responded.Count.ToString() ); + Console.WriteLine( "Unresponsive: " + query.Unresponsive.Count.ToString() ); + + query.Dispose(); + + for ( int i = 0; i < 100; i++ ) + { + client.Update(); + System.Threading.Thread.Sleep( 1 ); + } + } + } + + [TestMethod] + public void MultipleInternetList() + { + using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) + { + var queries = new List< Facepunch.Steamworks.ServerList.Request >(); + + for ( int i = 0; i < 10; i++ ) + queries.Add( client.ServerList.Test() ); + + for ( int i = 0; i < 100; i++ ) + { + client.Update(); + System.Threading.Thread.Sleep( 5 ); + + if ( queries.Any( x => x.Finished ) ) + break; + } + + foreach ( var query in queries ) + { + Console.WriteLine( "Responded: " + query.Responded.Count.ToString() ); + Console.WriteLine( "Unresponsive: " + query.Unresponsive.Count.ToString() ); + + client.Update(); + query.Dispose(); + client.Update(); + } + } + } + + [TestMethod] + public void HistoryList() + { + using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) + { + var query = client.ServerList.History( new Dictionary() ); + + 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() ); + + query.Dispose(); + + for ( int i = 0; i < 100; i++ ) + { + client.Update(); + System.Threading.Thread.Sleep( 1 ); + } + } + } + } +} diff --git a/Facepunch.Steamworks.Test/Stats.cs b/Facepunch.Steamworks.Test/Stats.cs new file mode 100644 index 0000000..21fa433 --- /dev/null +++ b/Facepunch.Steamworks.Test/Stats.cs @@ -0,0 +1,73 @@ +using System; +using System.Text; +using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Facepunch.Steamworks.Test +{ + [TestClass] + [DeploymentItem( "FacepunchSteamworksApi.dll" )] + [DeploymentItem( "steam_appid.txt" )] + public class Stats + { + [TestMethod] + public void UpdateStats() + { + using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) + { + client.Stats.UpdateStats(); + } + } + + [TestMethod] + public void UpdateSUpdateGlobalStatstats() + { + using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) + { + client.Stats.UpdateGlobalStats( 1 ); + client.Stats.UpdateGlobalStats( 3 ); + client.Stats.UpdateGlobalStats( 7 ); + } + } + + [TestMethod] + public void GetClientFloat() + { + using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) + { + var v = client.Stats.GetFloat( "deaths" ); + Console.WriteLine( v ); + } + } + + [TestMethod] + public void GetClientInt() + { + using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) + { + var v = client.Stats.GetInt( "deaths" ); + Console.WriteLine( v ); + } + } + + [TestMethod] + public void GetGlobalFloat() + { + using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) + { + var v = client.Stats.GetGlobalFloat( "deaths" ); + Console.WriteLine( v ); + } + } + + [TestMethod] + public void GetGlobalInt() + { + using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) + { + var v = client.Stats.GetGlobalInt( "deaths" ); + Console.WriteLine( v ); + } + } + } +} diff --git a/Facepunch.Steamworks/Client.ServerList.Request.cs b/Facepunch.Steamworks/Client.ServerList.Request.cs index e91232e..5bd5637 100644 --- a/Facepunch.Steamworks/Client.ServerList.Request.cs +++ b/Facepunch.Steamworks/Client.ServerList.Request.cs @@ -14,9 +14,6 @@ public class Request : IDisposable internal Client client; internal IntPtr Id; - private IntPtr m_pVTable; - private GCHandle m_pGCHandle; - public struct Server { public string Name { get; set; } @@ -56,8 +53,6 @@ public string ConnectionAddress } } - - internal static Server FromSteam( gameserveritem_t item ) { return new Server() @@ -100,21 +95,11 @@ internal static Server FromSteam( gameserveritem_t item ) /// public bool Finished = false; - internal Request() + internal Request( Client c ) { - // - // Create a fake vtable for Steam to respond to - // - var vt = new VTable() - { - responded = OnServerResponded, - nonresponsive = NonResponsive, - complete = Complete - }; + client = c; - m_pVTable = Marshal.AllocHGlobal( Marshal.SizeOf( typeof( VTable ) ) ); - Marshal.StructureToPtr( vt, m_pVTable, false ); - m_pGCHandle = GCHandle.Alloc( m_pVTable, GCHandleType.Pinned ); + client.OnUpdate += Update; } ~Request() @@ -122,88 +107,98 @@ internal Request() Dispose(); } + int lastCount = 0; + + internal List watchlist = new List(); + + private void Update() + { + if ( Id == IntPtr.Zero ) + return; + + // + // Add any servers we're not watching to our watch list + // + var count = client.native.servers.GetServerCount( Id ); + if ( count != lastCount ) + { + for ( int i = lastCount; i < count; i++ ) + { + watchlist.Add( i ); + } + + lastCount = count; + } + + // + // Remove any servers that respond successfully + // + watchlist.RemoveAll( x => + { + var info = client.native.servers.GetServerDetails( Id, x ); + if ( info.m_bHadSuccessfulResponse ) + { + OnServer( info ); + return true; + } + + return false; + } ); + + // + // If we've finished refreshing + // + if ( client.native.servers.IsRefreshing( Id ) == false ) + { + // + // Put any other servers on the 'no response' list + // + watchlist.RemoveAll( x => + { + var info = client.native.servers.GetServerDetails( Id, x ); + OnServer( info ); + return true; + } ); + + Finished = true; + client.OnUpdate -= Update; + client.native.servers.CancelQuery( Id ); + Id = IntPtr.Zero; + } + } + + private void OnServer( gameserveritem_t info ) + { + if ( info.m_bHadSuccessfulResponse ) + { + Responded.Add( Server.FromSteam( info ) ); + } + else + { + Unresponsive.Add( Server.FromSteam( info ) ); + } + + } + /// /// Disposing will end the query /// public void Dispose() { + client.OnUpdate -= Update; + // // Cancel the query if it's still running // - if ( !Finished && Id != IntPtr.Zero ) + if ( Id != IntPtr.Zero ) { if ( client.Valid ) client.native.servers.CancelQuery( Id ); Id = IntPtr.Zero; } - - // - // Release the pinned GC resources - // - if ( m_pVTable != IntPtr.Zero ) - { - Marshal.FreeHGlobal( m_pVTable ); - m_pVTable = IntPtr.Zero; - } - - if ( m_pGCHandle.IsAllocated ) - { - m_pGCHandle.Free(); - } } - private void Complete( IntPtr thisptr, IntPtr RequestId, int response ) - { - if ( RequestId != Id ) - throw new Exception( "Request ID is invalid!" ); - - Finished = true; - Id = IntPtr.Zero; - } - - private void NonResponsive( IntPtr thisptr, IntPtr RequestId, int iServer ) - { - if ( RequestId != Id ) - throw new Exception( "Request ID is invalid!" ); - - var info = client.native.servers.GetServerDetails( Id, iServer ); - Unresponsive.Add( Server.FromSteam( info ) ); - } - - private void OnServerResponded( IntPtr thisptr, IntPtr RequestId, int iServer ) - { - if ( RequestId != Id ) - throw new Exception( "Request ID is invalid!" ); - - var info = client.native.servers.GetServerDetails( Id, iServer ); - Responded.Add( Server.FromSteam( info ) ); - - System.Diagnostics.Debug.WriteLine( info.m_szServerName ); - } - - internal IntPtr GetVTablePointer() - { - return m_pGCHandle.AddrOfPinnedObject(); - } - - [StructLayout( LayoutKind.Sequential )] - internal class VTable - { - [UnmanagedFunctionPointer( CallingConvention.ThisCall )] - internal delegate void InternalServerResponded( IntPtr thisptr, IntPtr hRequest, int iServer ); - [UnmanagedFunctionPointer( CallingConvention.ThisCall )] - internal delegate void InternalServerFailedToRespond( IntPtr thisptr, IntPtr hRequest, int iServer ); - [UnmanagedFunctionPointer( CallingConvention.ThisCall )] - internal delegate void InternalRefreshComplete( IntPtr thisptr, IntPtr hRequest, int response ); - - [NonSerialized, MarshalAs(UnmanagedType.FunctionPtr)] - internal InternalServerResponded responded; - [NonSerialized, MarshalAs(UnmanagedType.FunctionPtr)] - internal InternalServerFailedToRespond nonresponsive; - [NonSerialized, MarshalAs(UnmanagedType.FunctionPtr)] - internal InternalRefreshComplete complete; - } } } } diff --git a/Facepunch.Steamworks/Client.ServerList.cs b/Facepunch.Steamworks/Client.ServerList.cs index 7c651af..2f113a3 100644 --- a/Facepunch.Steamworks/Client.ServerList.cs +++ b/Facepunch.Steamworks/Client.ServerList.cs @@ -48,25 +48,41 @@ public unsafe Request Test() //fixed ( void* a = array ) { - var request = new Request() - { - client = client - }; + var request = new Request( client ); - request.Id = client.native.servers.RequestInternetServerList( client.AppId, new IntPtr[] { }, request.GetVTablePointer() ); + request.Id = client.native.servers.RequestInternetServerList( client.AppId, new IntPtr[] { }, IntPtr.Zero ); return request; } } + class ResponseClass : ISteamMatchmakingServerListResponse + { + internal override IntPtr GetIntPtr() + { + return IntPtr.Zero; + } + + internal override void RefreshComplete( uint hRequest, uint response ) + { + throw new NotImplementedException(); + } + + internal override void ServerFailedToRespond( uint hRequest, int iServer ) + { + throw new NotImplementedException(); + } + + internal override void ServerResponded( uint hRequest, int iServer ) + { + throw new NotImplementedException(); + } + } + public unsafe Request History( Dictionary< string, string > filter ) { - var request = new Request() - { - client = client - }; - - request.Id = client.native.servers.RequestHistoryServerList( client.AppId, new IntPtr[] { }, request.GetVTablePointer() ); + var request = new Request( client ); + request.Id = client.native.servers.RequestHistoryServerList( client.AppId, new IntPtr[] { }, IntPtr.Zero ); return request; } diff --git a/Facepunch.Steamworks/Client.cs b/Facepunch.Steamworks/Client.cs index de3b14d..e23ee1a 100644 --- a/Facepunch.Steamworks/Client.cs +++ b/Facepunch.Steamworks/Client.cs @@ -139,7 +139,7 @@ public Client( uint appId ) public void Dispose() { - if ( native != null) + if ( native != null) { native.Dispose(); native = null; @@ -157,15 +157,23 @@ private void InternalOnWarning( int nSeverity, System.Text.StringBuilder text ) } } + internal event Action OnUpdate; + /// /// Should be called at least once every frame /// public void Update() { + if ( native == null ) + return; + Valve.Steamworks.SteamAPI.RunCallbacks(); Voice.Update(); Inventory.Update(); Networking.Update(); + + if ( OnUpdate != null ) + OnUpdate(); } public bool Valid diff --git a/Facepunch.Steamworks/Client/Stats.cs b/Facepunch.Steamworks/Client/Stats.cs index 6a55211..8d0ff39 100644 --- a/Facepunch.Steamworks/Client/Stats.cs +++ b/Facepunch.Steamworks/Client/Stats.cs @@ -44,22 +44,30 @@ public void UpdateGlobalStats( int days = 1 ) public int GetInt( string name ) { - return 0; + int data = 0; + client.native.userstats.GetStat( name, ref data ); + return data; } - public int GetGlobalInt( string name ) + public long GetGlobalInt( string name ) { - return 0; + long data = 0; + client.native.userstats.GetGlobalStat( name, ref data ); + return data; } - public int GetFloat( string name ) + public float GetFloat( string name ) { - return 0; + float data = 0; + client.native.userstats.GetStat0( name, ref data ); + return data; } - public int GetGlobalFloat( string name ) + public double GetGlobalFloat( string name ) { - return 0; + double data = 0; + client.native.userstats.GetGlobalStat0( name, ref data ); + return data; } }